home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / batchut / bat2ex13.zip / BAT2EXE.ASM next >
Assembly Source File  |  1990-10-07  |  120KB  |  3,972 lines

  1.         page    66,132
  2. ;============================================================================
  3. ; BAT2EXEC.COM - a batch file compiler
  4. ;
  5. ; Syntax:
  6. ;    BAT2EXEC filename
  7. ;
  8. ; Revision History:
  9. ;
  10. ;    Version 1.0    Initial Release     PC Magazine Vol 9 Num 14
  11. ;    Version 1.1    Bug Fixes               July 19, 1990
  12. ;    Version 1.2    Bug Fixes               July 28, 1990
  13. ;                       Added ability to read large BAT files.
  14. ;       Version 1.3     PATH cmd fix.           Oct.  3, 1990
  15. ;             Echo cmd fix
  16. ;                       Other small bug fixes.
  17. ;
  18. ;============================================================================
  19.  
  20.         code    segment
  21.         assume    cs:code
  22.  
  23.         org    2ch
  24. local_environment    dw    ?            ;Word containing the segment
  25.                         ;  of the program's env. block.
  26.         org    80h
  27. command_tail    db    ?            ;Offset of the command tail.
  28.  
  29.         org    100h
  30.  
  31. main:        jmp    initialize
  32. program     db    13,10,"BAT2EXEC 1.3 "
  33. copyright    db    "(c) 1990 Ziff Communications Co.",10,13
  34. author        db    "PC Magazine ",254," Douglas Boling"
  35.         db    10,13,"$",1Ah
  36. ;----------------------------------------------------------------------------
  37. ;Equates used to find data offsets in the compiled program.
  38. ;----------------------------------------------------------------------------
  39. BUFF_SIZE        equ    255            ;Size of runtime buffers
  40.  
  41. std_data_size    equ    offset data_end - data_start
  42. code_start_ptr    equ    [bp + offset code_start - offset data_start]
  43. com_stack_ptr    equ    [bp + offset stack_ptr - offset data_start]
  44. com_prog_size    equ    [bp + offset prog_segsize - offset data_start]
  45. com_label_start equ    [bp + offset label_list_strt - offset data_start]
  46. parse_buff    equ    [bp + offset prse_buff_ptr - offset data_start]
  47. parse2_buff    equ    [bp + offset prs2_buff_ptr - offset data_start]
  48. exec_buff    equ    [bp + offset exec_buff_ptr - offset data_start]
  49. forloop_buff    equ    [bp + offset for_buff_ptr - offset data_start]
  50. forloop_ptr    equ    [bp + offset floop_ptr - offset data_start]
  51. stdout_hdl    equ    [bp + offset file_handle1 - offset data_start]
  52. outfile_hdl    equ    [bp + offset file_handle2 - offset data_start]
  53. stdin_hdl    equ    [bp + offset file_handle3 - offset data_start]
  54. infile_hdl    equ    [bp + offset file_handle4 - offset data_start]
  55. environment_seg equ    [bp + offset master_env - offset data_start]
  56. dos_version    equ    [bp + offset version_num - offset data_start]
  57. process_rc    equ    [bp + offset proc_rc - offset data_start]
  58. shift_count    equ    [bp + offset shift_cnt - offset data_start]
  59.  
  60. code_call_size    equ    offset code_call_end - offset code_call
  61. code_jmp_size    equ    offset code_jmp_end - offset code_jmp
  62. code_jc_size    equ    offset code_jc_end - offset code_jc
  63. code_jnc_size    equ    offset code_jnc_end - offset code_jnc
  64. code_jmpdis_size   equ       offset code_jmpdis_end - offset code_jmpdis
  65. code_leasi_size equ    offset code_leasi_end - offset code_leasi
  66. code_movsi_size equ    offset code_movsi_end - offset code_movsi
  67. code_movsiim_size equ    offset code_movsiim_end - offset code_movsiim
  68. code_leadi_size equ    offset code_leadi_end - offset code_leadi
  69. code_movdi_size equ    offset code_movdi_end - offset code_movdi
  70. code_movdiim_size equ    offset code_movdiim_end - offset code_movdiim
  71. ;============================================================================
  72. ;Compiler data
  73. ;============================================================================
  74. command_table    db    "IF",0                  ;Commands processed by
  75.         db    "REM",0                 ;  compiler
  76.         db    "FOR",0
  77.         db    "ECHO",0
  78.         db    "GOTO",0
  79.         db    "EXIT",0
  80.         db    "PAUSE",0
  81.         db    "SHIFT",0
  82.         db    "SET",0
  83.         db    "CALL",0
  84.         db    "PATH",0
  85.         db    "PROMPT",0
  86.         db    "CD",0                  ;DOS commands internal to
  87.         db    "MD",0                  ;  command.com.
  88.         db    "RD",0
  89.         db    "CLS",0
  90.         db    "DIR",0
  91.         db    "DEL",0
  92.         db    "REN",0
  93.         db    "VER",0
  94.         db    "VOL",0
  95.         db    "CTTY",0
  96.         db    "CHCP",0
  97.         db    "TYPE",0
  98.         db    "COPY",0
  99.         db    "DATE",0
  100.         db    "TIME",0
  101.         db    "ERASE",0
  102.         db    "CHDIR",0
  103.         db    "MKDIR",0
  104.         db    "RMDIR",0
  105.         db    "BREAK",0
  106.         db    "RENAME",0
  107.         db    "DELETE",0
  108.         db    "VERIFY",0
  109.         db    "COMMAND",0,0
  110.  
  111. batcmd_jmptbl    dw    if_cmd            ;if command
  112.         dw    rem_cmd         ;rem command
  113.         dw    for_cmd         ;for command
  114.         dw    echo_cmd        ;echo command
  115.         dw    goto_cmd        ;goto command
  116.         dw    rem_cmd         ;exit command
  117.         dw    pause_cmd        ;pause command
  118.         dw    shift_cmd        ;shift command
  119.         dw    set_cmd         ;set command
  120.  
  121.         dw    internal_cmd        ;call command
  122.         dw    path_cmd         ;Path command
  123.         dw    prompt_cmd         ;Prompt command
  124.         dw    internal_cmd        ;DOS internal command
  125.         dw    external_cmd        ;DOS program
  126.         dw    label_cmd        ;Process BAT label
  127. batcmd_jmptbl1    =    $
  128.  
  129. ifstr1        db    "ERRORLEVEL"
  130. ifstr2        db    "EXIST"
  131.  
  132. internal_cmdsw    db    "/C "                   ;Switch for transient commands
  133.  
  134. for_active_flag db    0            ;Set if parsing a FOR loop
  135. goto_active    db    0            ;Set if goto parsed
  136. goto_data_ptr    dw    0            ;Data offset of last goto    
  137.  
  138. temp1        dw    0            ;Temp data storage.
  139.  
  140. cmd_switches    db    ?            ;Used if command line switches
  141. cmd_switch_end    =    $            ;  needed.
  142.  
  143. last_routine    dw    offset init_code_next    ;Last canned routine used.
  144.  
  145. codebuff_start    dw    0            ;Buffer to construct the code
  146. codebuff_ptr    dd    0            ;  image of the COM file.
  147.  
  148. databuff_start    dw    ?            ;Buffer to hold the data
  149. databuff_end    dw    ?            ;  image of the COM file.
  150.  
  151. firstlabel    dw    -1            ;Ptr to 1st label in COM file
  152.  
  153. outbuff_ptr    dd    0            ;Buffer to hold the final
  154. outbuff_end    dw    0            ;  image of the COM file.
  155.  
  156. quote_flag    db    0            ;Disable translate flag
  157. redirect_in    db    0            ;Input redirection flag
  158. redirect_out    db    0            ;Output redirection flag
  159.  
  160. pipe_toggle    db    0            ;Piping file flag
  161. pipein_file    dw    0
  162. pipein_flag    db    0
  163. pipeout_file    dw    0
  164. pipeout_flag    db    0
  165. pipe1_file    dw    0
  166.         db    "T^M^P_$1.!!!",0    ;Name of piping file 1
  167. pipe2_file    dw    0
  168.         db    "T^M^P_$2.!!!",0    ;Name of piping file 2
  169.  
  170. inbuff_ptr    dw    offset end_of_code+512    ;Buffer for BAT file
  171. inbuff_size    dw    1024             ;Size of input buffer
  172.  
  173. file_handle    dw    -1            ;Handle of BAT file
  174. file_linecount    dw    0            ;Line number being processed.
  175.  
  176. com_string    db    ".COM",0        ;Extension for output file
  177. outfile_name    db    13 dup (" ")        ;Name of output file.
  178.  
  179. filemsg1    db    13,10,"Error in line $" ;File identification message.
  180.  
  181. errmsg0     db    "Need DOS 2.0 or greater$"
  182. errmsg1     db    13,10,"Syntax: BAT2EXEC filename.ext",13,10,"$"
  183. errmsg2     db    "Can",39,"t find input file$"
  184. errmsg3     db    "Not enough memory$"
  185. errmsg4     db    "No input file specified$"
  186. errmsg5     db    "COM file size too big$"
  187. errmsg6     db    "Syntax error$"
  188. errmsg7     db    "Compiler data buffer full$"
  189. errmsg8     db    "Label defined more than once$"
  190. errmsg9     db    "Label "
  191. errmsg9labl    db    8 dup (" ")
  192.         db    "not found$"
  193. errmsg10    db    "Illegal disk specified$"
  194. errmsg11    db    "FOR loops cannot be nested$"
  195.  
  196. endmsg        db    13,10,"$"
  197.  
  198. ;----------------------------------------------------------------------------
  199. ; Start of compiler code.
  200. ;----------------------------------------------------------------------------
  201. initialize    proc    near
  202.         assume    cs:code,ds:code,es:code
  203.         mov    dx,offset program    ;Display copyright message.
  204.         mov    ah,9
  205.         int    21h
  206.         cld                ;Set string operations 'up.'
  207.         mov    ah,30h            ;Get DOS version, run only
  208.         int    21h            ;  if 2.0 or greater.
  209.         xchg    al,ah            ;Swap major, minor numbers
  210.         mov    dx,offset errmsg0    ;Bad DOS version
  211.         cmp    ah,2
  212.         jb    jmp_disp_error
  213.  
  214.         mov    sp,offset end_of_code + 512    ;Move stack
  215.         mov    ah,4ah                ;Reduce memory
  216.         mov    bx,1000h            ; allocation to 64K
  217.         int    21h
  218.  
  219.         mov    ax,inbuff_ptr        ;Compute start of buffer for
  220.         add    ax,inbuff_size        ;  COM file data.
  221.         mov    databuff_start,ax
  222.  
  223.         mov    ah,48h            ;Allocate memory block for
  224.         mov    bx,1000h        ;  intermediate buffer.
  225.         int    21h
  226.         mov    dx,offset errmsg3    ;Not enough memory msg
  227.         jc    jmp_disp_error
  228.         mov    word ptr codebuff_ptr[2],ax    ;Save segment.
  229.  
  230.         mov    ah,48h            ;Allocate memory block for
  231.         mov    bx,1000h        ;  output file buffer.
  232.         int    21h
  233.         jc    jmp_disp_error
  234.         mov    word ptr outbuff_ptr[2],ax    ;Save segment.
  235. ;
  236. ;Parse the command line for switches.
  237. ;
  238.         mov    si,offset command_tail
  239.         xor    cx,cx
  240.         or    cl,[si]         ;Get command line length
  241.         je     init_0                  ;If zero, report no filename
  242.         inc    si
  243. parse_cmdline_l1:
  244.         xor    bl,bl            ;Search for the next
  245.         call    scan4char        ;  non-space character.
  246.         jnc    init_1                  ;If zero, report no filename
  247. init_0:
  248.         mov    dx,offset errmsg1
  249.         jmp    short jmp_disp_error    ;If none, report no filename
  250. init_1:
  251.         mov    al,[si]
  252.         cmp    al,"/"                  ;See if command switch
  253.         je    parse_error
  254.         call    loadbatfile        ;Load input BAT file
  255.         jc    jmp_disp_error
  256.         jmp    short parse_cmdline_end
  257. parse_error:
  258.         mov    dx,offset errmsg2
  259. jmp_disp_error:
  260.         jmp    disp_error
  261. parse_cmdline_end:
  262. ;
  263. ;Compile BAT file line by line.
  264. ;
  265.         mov    si,inbuff_ptr        ;SI points to input BAT file
  266.         mov    di,databuff_start    ;DI points to COM file data.
  267.         add    di,std_data_size    ;Make room for std data set.
  268. new_line:
  269.         inc    file_linecount        ;Inc line number
  270. new_line1:
  271.         xor    bl,bl            ;Look for 1st character
  272.         call    scan4char        ;If nothing on line, check
  273.         jc    comp_endcheck        ;  for EOF
  274.         call    redirect_check
  275.         cmp    byte ptr [si],'@'    ;See if non echo prefix
  276.         jne    comp_1
  277.         inc    si            ;Move past @
  278. comp_1:
  279.         call    parse            ;Parse 1st word in the line.
  280.         jc     jmp_disp_error        
  281.         jmp    short new_line
  282. comp_endcheck:
  283.         cmp    al,13            ;See if carrage return, if so
  284.         je    new_line        ;  continue.
  285.         cmp    file_handle,-1        ;If at end of buffer, check
  286.         je    comp_end        ;  to see if any more of the
  287.         call    loadbatfile        ;  file to read.
  288.         jc    jmp_disp_error
  289.         mov    si,inbuff_ptr        ;Reset SI to start of buffer.
  290.         jmp    short new_line1        
  291. comp_end:
  292. ;
  293. ;Inline code complete, append terminate code.
  294. ;
  295.         call    redirect_close
  296.         mov    databuff_end,di     ;Save ptr to end of data.
  297.         les    di,codebuff_ptr
  298.         assume    es:nothing
  299.         mov    si,offset end_code    ;Append terminate code
  300.         mov    cx,offset end_code_end-offset end_code
  301.         rep    movsb
  302.         mov    word ptr codebuff_ptr,di ;Save ptr to end of COM code.
  303. ;
  304. ;File processed. Assemble data and code into one routine.  Start by
  305. ;stringing the canned routines together using the links set by the
  306. ;INCLUDE routine.
  307. ;
  308.         les    di,outbuff_ptr         ;Get ptr to output buffer
  309.         mov    si,offset init_code_next ;  for COM file.
  310. file_1:     mov    cx,[si-2]        ;Get size of routine
  311.         push    [si]            ;Save pointer to next routine
  312.         add    si,4            ;Skip past number of links
  313.         rep    movsb            ;Copy routine to COM file.
  314.         pop    si
  315.         or    si,si            ;See if last routine
  316.         jne    file_1            ;No, loop back.
  317. ;
  318. ;Save starting offset of data to be used by the COM program.
  319. ;
  320.         mov    bp,offset data_start_ptr-offset init_code
  321.         mov    ax,100h         ;AX = end pointer
  322.         add    ax,di            ;Add length of canned routines.
  323.         mov    es:[bp],ax        ;Save data start pointer
  324.         mov    bp,di            ;Use BP as starting data offset
  325.  
  326.         mov    si,databuff_start    ;Compute length of COM data
  327.         mov    cx,databuff_end     ;  plus the canned routines.
  328.         sub    cx,si
  329.         add    ax,cx            ;Add data length to end ptr
  330. ;
  331. ;Now that we have the length of the canned routines and the data, we can
  332. ;compute the starting offset of the inline code.  Use this number to adjust
  333. ;the jump table entries in the label list.  While fixing offsets check to
  334. ;see that all labels have code offsets, if not, print no label error msg.
  335. ;When complete, append data to file.
  336. ;
  337.         mov    bx,offset firstlabel    ;Get pointer to the first label
  338.         mov    dx,[bx]         ;Get offset to 1st label entry
  339.         add    dx,bx            ;Add in BX to get absolute off
  340. file_11:
  341.         cmp    word ptr [bx],-1    ;See if at end of label list.
  342.         je    file_13
  343.         add    bx,[bx]         ;Get next in list
  344.         cmp    word ptr [bx+2],-1    ;See if label ptr to code
  345.         je    file_12         ;  initialized. No, error.
  346.         add    [bx+2],ax        ;Add starting offset of code
  347.         jmp    short file_11
  348. file_12:
  349.         mov    si,bx            ;Label not defined as a
  350.         add    si,5            ;  destination.  Print error
  351.         xor    cx,cx            ;  message inc lost label.
  352.         mov    cl,[bx+4]        ;Get size of label
  353.         push    cs
  354.         pop    es
  355.         mov    di,offset errmsg9labl
  356.         rep    movsb
  357.         mov    dx,offset errmsg9    ;Label not found msg
  358.         jmp    disp_error
  359. file_13:
  360.         rep    movsb            ;Append data to COM file.
  361.         sub    dx,databuff_start    ;Set pointer to 1st label list
  362.         mov    es:com_label_start,dx    ;Initialize pointer.
  363. ;
  364. ;Append the inline code to the program.
  365. ;
  366.         mov    ax,100h
  367.         add    ax,di
  368.         mov    es:code_start_ptr,ax    ;Save offset of main code.
  369.  
  370.         mov    cx,word ptr codebuff_ptr
  371.         mov    si,codebuff_start    ;Get pointer to code
  372.         mov    ds,word ptr codebuff_ptr[2]
  373.         assume    ds:nothing
  374.         sub    cx,si            ;Get size of code
  375.         add    ax,cx            ;Make sure canned routines
  376.         jnc    file_2            ;  and data < 64 K bytes.
  377. file_too_big:    mov    dx,offset errmsg5    ;COM file too big msg
  378.         jmp    disp_error
  379. file_2:
  380.         rep    movsb            ;Append inline code.
  381. ;
  382. ;Compute the size of the data buffers and the stack used by the COM program.
  383. ;Write these numbers to the COM file data area.
  384. ;
  385.         push    cs
  386.         pop    ds
  387.         assume    ds:code
  388.         add    ax,512            ;Add room for stack
  389.         jc    file_too_big
  390.         and    ax,0fffeh        ;Set stack on even word.
  391.         mov    es:com_stack_ptr,ax    ;Save run time stack pointer
  392.         add    ax,2            ;Make room for buff length word
  393.         mov    es:parse_buff,ax    ;Save ptr to parsing buffer.
  394.         add    ax,BUFF_SIZE+2        ;Add room for buffer 2
  395.         jc    file_too_big
  396.         mov    es:parse2_buff,ax    ;Save ptr to parsing buffer 2
  397.         add    ax,BUFF_SIZE+2        ;Add room for buffer
  398.         jc    file_too_big
  399.         mov    es:exec_buff,ax        ;Save ptr to exec buffer 
  400.         add    ax,BUFF_SIZE+2        ;Add room for buffer
  401.         jc    file_too_big
  402.         mov    es:forloop_buff,ax    ;Save ptr to For loop buffer
  403.         add    ax,BUFF_SIZE        ;Add room for buffer
  404.         jc    file_too_big
  405.  
  406.         mov    outbuff_end,di        ;Save end pointer to file
  407.         add    ax,15
  408.         jc    file_3            ;Compute size of COM file
  409.         mov    cl,4            ;  in paragraphs.
  410.         shr    ax,cl
  411.         mov    es:com_prog_size,ax    ;Save file size
  412.         mov    byte ptr es:shift_count,0    ;Clear shift count
  413.         mov    byte ptr es:process_rc,0    ;Clear return code
  414. file_3:
  415. ;
  416. ;Write file to disk.
  417. ;
  418.         mov    ah,3ch            ;Create file
  419.         xor    cx,cx            ;Normal attributes
  420.         mov    dx,offset outfile_name    ;Name of file
  421.         int    21h
  422.  
  423.         mov    bx,ax            ;Copy handle
  424.         mov    ah,40h            ;Write file
  425.         push    ds
  426.         lds    dx,outbuff_ptr        ;Get start of buffer
  427.         mov    cx,cs:[outbuff_end]    ;Get number of bytes to write
  428.         sub    cx,dx
  429.         int    21h            ;Write file to disk
  430.         pop    ds
  431.  
  432.         mov    ah,3eh            ;Close file
  433.         int    21h
  434. ;
  435. ;Compile complete. Clean up and end.
  436. ;
  437. good_exit:
  438.         xor    al,al            ;Return code = 0
  439. exit:
  440.         push    ax            ;Save return code
  441.         mov    ah,49h            ;Release memory block used
  442.         mov    es,word ptr cs:[codebuff_ptr+2] ;  for file buffer.
  443.         int    21h
  444.  
  445.         mov    bx,file_handle
  446.         cmp    bx,-1            ;See if input file closed.
  447.         jne    exit_1            ;  If not, do so.
  448.         mov    ah,3eh            ;Close file.
  449.         int    21h
  450. exit_1:
  451.         pop    ax            ;Get back return code
  452.         mov    ah,4Ch            ;Terminate
  453.         int    21h
  454. ;
  455. ;Display error message.
  456. ;
  457. disp_error:
  458.         push    cs
  459.         pop    ds
  460.         assume    ds:code
  461.         cmp    file_linecount,0
  462.         je    disp_error1        ;If processing a file, print
  463.         push    dx            ;  a message informing the
  464.         mov    dx,offset filemsg1    ;  user the line that
  465.         call    printmsg        ;  contained the error.
  466.         mov    ax,file_linecount
  467.         call    hex2asc
  468.         mov    dx,offset endmsg
  469.         call    printmsg
  470.         pop    dx
  471. disp_error1:
  472.         call    printmsgcr        ;print string
  473.         mov    al,01            ;Terminate with RC = 1
  474.         jmp    short exit
  475.  
  476. ;-----------------------------------------------------------------------------
  477. ; PARSE  Parse a statment.
  478. ; Entry:  SI - Pointer to string to parse.
  479. ;      DI - Pointer to end of COM file data.
  480. ; Exit:   CF - Set if error.
  481. ;      SI - Updated.
  482. ;-----------------------------------------------------------------------------
  483. parse        proc    near
  484.         mov    bx,14
  485.         mov    al,[si]         ;See if label, if so, skip 
  486.         cmp    al,":"            ;  cmd search.
  487.         je    parse_2
  488.  
  489.         mov    bx,12
  490.         cmp    al,"%"                  ;See if cmd line param or env
  491.         je    parse_2         ;  var. If so, internal cmd
  492.  
  493.         mov    ax,[si+1]        ;See if change to default disk
  494.         cmp    al,":"
  495.         jne    parse_1
  496.  
  497.         mov    bx, 12            ;Set internal command.
  498.         cmp    ah," "
  499.         jbe    parse_2
  500. parse_1:
  501.         call    capsalpha        ;Capitalize batch command
  502.         push    di            ;Search list of BAT cmds.
  503.         mov    di,offset command_table
  504.         call    findstr
  505.         pop    di
  506. parse_2:
  507.         push    bx            ;Scan past command except for
  508.         cmp    bx,8            ;  external progs, inter cmds,
  509.         ja    parse_3         ;  and labels.
  510.         mov    bl,1
  511.         call    scan4char
  512.         jnc    parse_3         ;If end of line, back up to
  513.         dec    si            ;  show CR.
  514. parse_3:
  515.         pop    bx
  516.         shl    bx,1            ;Compute offset of routine to
  517.         add    bx,offset batcmd_jmptbl ;  call.
  518.         call    [bx]            ;Call routine to compile line.
  519.         ret
  520. parse        endp
  521.  
  522. ;-----------------------------------------------------------------------------
  523. ; FINDSTR  determines if a string is in a list.
  524. ; Entry:  SI - Pointer to ASCII string to find.
  525. ;      DI - Pointer to list of ASCIIZ strings.
  526. ;      CX - Size of string
  527. ; Exit:   CF - Clear if string found
  528. ;      BX - If CF clear, index into list
  529. ;-----------------------------------------------------------------------------
  530. findstr     proc    near
  531.         push    cx
  532.         push    es
  533.         push    cs            ;Point ES:DI to table of
  534.         pop    es            ;  batch commands.
  535.         xor    dx,dx
  536.         or     dx,cx            ;Save length of string
  537.         je    finds_3
  538.         xor    bx,bx            ;Zero index counter
  539. finds_1:
  540.         push    si
  541.         mov    cx,dx            ;Restore command size
  542.         repe    cmpsb            ;Compare command
  543.         pop    si
  544.         je    string_found
  545.         inc    bx
  546.         xor    al,al
  547.         cmp    [di-1],al
  548.         jne    finds_2
  549.         dec    di
  550. finds_2:
  551.         mov    cx,10            ;Scan to next zero
  552.         repne    scasb
  553.         cmp    byte ptr [di],0     ;See if second zero. If so
  554.         jne    finds_1         ;  end of list.
  555. finds_3:
  556.         mov    bx,13
  557.         stc                ;Indicate string not found
  558. findstr_exit:
  559.         pop    es
  560.         pop    cx
  561.         ret
  562. string_found:
  563.         cmp    bx,12            ;If past the BAT commands,
  564.         jb    findstr_3        ;  then it is an internal cmd.
  565.         mov    bx,12
  566. findstr_3:
  567.         clc                ;Set string found flag
  568.         jmp    short findstr_exit
  569. findstr     endp
  570.  
  571. ;-----------------------------------------------------------------------------
  572. ; CAPSWORD capitalizes word pointed to by SI
  573. ; Entry:  SI - Pointer to ASCII word to capitalize
  574. ; Exit:   CX - Size of word
  575. ;-----------------------------------------------------------------------------
  576. capsalpha    proc near
  577.         assume    ds:nothing,es:nothing
  578.         push    ax
  579.         xor    ax,ax            ;Exit on non-alpha chars
  580.         jmp    short capsword_entry2
  581. capsalpha    endp
  582.  
  583. ;-----------------------------------------------------------------------------
  584. ; CAPSWORD capitalizes word pointed to by SI
  585. ; Entry:  SI - Pointer to ASCII word to capitalize
  586. ; Exit:   CX - Size of word
  587. ;-----------------------------------------------------------------------------
  588. capsword    proc near
  589.         assume    ds:nothing,es:nothing
  590.         push    ax
  591.         mov    ah,1            ;Ignore extra characters
  592. capsword_entry2:
  593.         push    di
  594.         push    si
  595.         push    es
  596.         push    ds            ;Set ES:DI = DS:SI
  597.         pop    es
  598.         mov    di,si
  599.         xor    cx,cx            ;Clear byte counter.
  600. caps_1:
  601.         lodsb                ;Get character
  602.         cmp    al," "                  ;Allow any non-space character
  603.         jbe    caps_exit
  604.         cmp    al,"a"                  ;If between a and z,
  605.         jb    caps_3           ;  capitalize it.
  606.         cmp    al,"z"
  607.         ja    caps_exit
  608.         and    al,0DFh
  609. caps_2:
  610.         stosb                ;Save character
  611.         inc    cx            ;Inc byte counter
  612.         jmp    short caps_1
  613. caps_3:
  614.         or    ah,ah            ;See if we should check 
  615.         jne    caps_2            ;  non-alpha chars.
  616.         cmp    al,'Z'
  617.         ja    caps_exit
  618.         cmp    al,'A'
  619.         jae    caps_2
  620. caps_exit:
  621.         pop    es
  622.         pop    si
  623.         pop    di
  624.         pop    ax
  625.         ret
  626. capsword    endp
  627.  
  628. ;-----------------------------------------------------------------------------
  629. ; REDIRECT CLOSE post process redirection commands
  630. ; Entry:  DI - Pointer to end of COM file data.
  631. ; Exit:   CF - Set if error.
  632. ;      Batch file line updated to remove any redirection symbols
  633. ;-----------------------------------------------------------------------------
  634. redirect_close    proc    near
  635.         assume    cs:code,ds:code
  636.         cmp    redirect_in,0        ;See if redirecton active
  637.         je    redirclose_1
  638.         mov    redirect_in,0
  639.         mov    bx,offset redirci_next    ;Append close redirect file
  640.         call    include_code        ;  routine to code.
  641.         xor    cx,cx
  642.         call    inline_code
  643. redirclose_1:
  644.         cmp    redirect_out,0        ;See if redirecton active
  645.         je    redirclose_2
  646.         mov    redirect_out,0
  647.         mov    bx,offset redirco_next    ;Append close redirect file
  648.         call    include_code        ;  routine to code.
  649.         xor    cx,cx
  650.         call    inline_code
  651. redirclose_2:
  652.         cmp    pipein_flag,0        ;See if in pipe curr active
  653.         je     redirclose_3
  654.         mov    dx,pipein_file        ;Get offset of input pipe file
  655.         mov    cx,1            ;Indicate parameter type
  656.         mov    bx,offset redirdel_next    ;Delete the piping file
  657.         call    include_code
  658.         call    inline_code        
  659.         mov    pipein_flag,0        ;Clear flag
  660. redirclose_3:
  661.         cmp    pipeout_flag,0        ;See if out pipe curr active
  662.         je     redirclose_exit
  663.         mov    dx,pipeout_file        ;Get offset of input pipe file
  664.         xor    bx,bx            ;Add output redirection code
  665.         xor    ax,ax            ;  to file.
  666.         call    redirect_openi
  667.         mov    pipein_flag,1        ;Set pipe input flag
  668.         mov    pipeout_flag,0        ;Clear pipe output flag
  669.         mov    pipein_file,dx        ;Copy pointer to filename
  670. redirclose_exit:
  671.         ret
  672. redirect_close    endp
  673.  
  674. ;-----------------------------------------------------------------------------
  675. ; REDIRECT CHECK process redirection commands
  676. ; Entry:  SI - Pointer to current BAT file line
  677. ;      DI - Pointer to end of COM file data.
  678. ; Exit:   CF - Set if error.
  679. ;      Batch file line updated to remove any redirection symbols
  680. ;-----------------------------------------------------------------------------
  681. redirect_check    proc    near
  682.         assume    cs:code,ds:code
  683.         push    si
  684.         call    redirect_close
  685.         mov    quote_flag,0
  686. redirect_1:
  687.         mov    bp,si            ;Save current position
  688.         lodsb
  689.         cmp    al,'"'                  ;See if quote
  690.         jne    redirect_2
  691.         not    quote_flag
  692. redirect_2:
  693.         cmp    quote_flag,0        ;Ignore characters in quotes
  694.         jne    redirect_1
  695. ;
  696. ; Check for piping
  697. ;
  698.         cmp    al,'|'                  ;Check for piping symbol
  699.         jne    redirect_5 
  700.         mov    byte ptr [si-1],13    ;Replace | with CR
  701.  
  702.         mov    bx,offset pipe1_file    ;Get offset of pipe file to
  703.         cmp    pipe_toggle,0        ;  use.  Alternate files so
  704.         jne    redirect_3         ;  that input and output files
  705.         mov    bx,offset pipe2_file    ;  don't get mixed up.
  706. redirect_3:
  707.         not    pipe_toggle
  708.         xor    dx,dx            ;If file not already used, 
  709.         or     dx,[bx]            ;  load the filename into 
  710.         jne    redirect_4         ;  the COM data buffer.
  711.         mov    dx,di
  712.         sub    dx,databuff_start    ;Compute offset of filename
  713.         mov    [bx],dx            ;Save pointer to filename
  714.         lea    si,[bx+2]        ;Get address of filename
  715.         mov    ah,1    
  716.         call    copy_string        ;Copy name to COM data buffer
  717.         xor    al,al            ;Terminate filename with zero
  718.         stosb
  719. redirect_4:
  720.         mov    pipeout_file,dx
  721.         mov    pipeout_flag,1
  722.         xor    bx,bx            ;Add output redirection code
  723.         xor    ax,ax            ;  to file.
  724.         call    redirect_openo
  725.         jmp    short redirect_exit    ;Terminate line scan.
  726. ;
  727. ; Check for output redirection
  728. ;
  729. redirect_5:
  730.         cmp    al,'>'                  ;Check for redirect out
  731.         jne    redirect_7
  732.         xor    bx,bx
  733.         cmp    byte ptr [si],'>'       ;Check for append redirect
  734.         jne    redirect_6
  735.         lodsb                ;Remove 2nd >
  736.         inc    bx
  737. redirect_6:
  738.         push    bx            ;Save append flag
  739.         xor    bl,bl
  740.         call    scan4char        ;Get filename
  741.         mov    dx,di
  742.         mov    ah,1            ;Copy only one word
  743.         call    copy_string
  744.         xor    al,al            ;Terminate name with zero
  745.         stosb
  746.         sub    dx,databuff_start    ;Compute offset of filename
  747.         pop    ax
  748.         call    redirect_openo
  749.         call    erase_redirect        ;Erase redirect from line.
  750.         jmp    short redirect_1
  751. redirect_7:
  752.         cmp    al,'<'                  ;Check for redirect in
  753.         jne    redirect_10
  754.         xor    bl,bl
  755.         call    scan4char        ;Get filename
  756.         mov    dx,di
  757.         mov    ah,1            ;Copy only one word
  758.         call    copy_string
  759.         xor    al,al            ;Terminate name with zero
  760.         stosb
  761.         sub    dx,databuff_start    ;Compute offset of filename
  762.         call    redirect_openi
  763.         call    erase_redirect        ;Erase redirect from line.
  764.         jmp    redirect_1
  765. redirect_10:
  766.         cmp    al,13
  767.         je    redirect_exit
  768.         jmp    redirect_1
  769. redirect_exit:
  770.         clc
  771.         pop    si
  772.         ret
  773. redirect_check    endp
  774.  
  775. ;-----------------------------------------------------------------------------
  776. ; REDIRECT OPENO process redirection commands
  777. ; Entry:  AX - 1 = append file.
  778. ; Entry:  DX - Offset from data buffer start of file name
  779. ;      BX - 0 no translation of filename.
  780. ;-----------------------------------------------------------------------------
  781. redirect_openo    proc    near
  782.         assume    cs:code,ds:code
  783.         push    si
  784.         push    ax            ;Save append flag
  785.         mov    cx,0031h        ;Indicate parameter type
  786.         or    bx,bx            ;See if env var or cmd line
  787.         je    redirect_oo1        ;  parms.
  788.  
  789.         mov    bx,offset procstr_next    ;Get offset of translate
  790.         call    include_code        ;  routine. Include if needed.
  791.  
  792.         mov    bx,offset prse_buff_ptr - offset data_start
  793.         mov    cx,0032h        ;Indicate parameter type
  794.         call    inline_code        ;Insert translate code.
  795. redirect_oo1:
  796.         mov    bx,offset rediroo_next    ;Append open redirect file
  797.         call    include_code
  798.         pop    bx            ;Restore append flag
  799.         call    inline_code
  800.         mov    redirect_out,1        ;Set redirect active flag
  801.         pop    si
  802.         ret
  803. redirect_openo    endp
  804.  
  805. ;-----------------------------------------------------------------------------
  806. ; REDIRECT OPENI loads code to open a file for input redirection
  807. ; Entry:  DX - Offset from data buffer start of file name
  808. ;      BX - 0 no translation of filename.
  809. ;-----------------------------------------------------------------------------
  810. redirect_openi    proc    near
  811.         assume    cs:code,ds:code
  812.         push    si
  813.         mov    cx,1            ;Indicate parameter type
  814.         or    bx,bx            ;See if env var or cmd line
  815.         je    redirect_oi1        ;  parms.
  816.  
  817.         mov    bx,offset procstr_next    ;Get offset of translate
  818.         call    include_code        ;  routine. Include if needed.
  819.  
  820.         mov    bx,offset prse_buff_ptr - offset data_start
  821.         mov    cx,2            ;Indicate parameter type
  822.         call    inline_code        ;Insert translate code.
  823. redirect_oi1:
  824.         mov    bx,offset rediroi_next    ;Append open redirect file
  825.         call    include_code
  826.         call    inline_code
  827.         mov    redirect_in,1        ;Set redirect active flag
  828.         pop    si
  829.         ret
  830. redirect_openi    endp
  831.  
  832. ;-----------------------------------------------------------------------------
  833. ; ERASE REDIRECT
  834. ; Entry:  BP - Pointer to redirect character
  835. ;      SI - Pointer to end of redirect phrase.
  836. ;-----------------------------------------------------------------------------
  837. erase_redirect    proc    near
  838.         assume    cs:code,ds:code
  839.         push    di            ;Save ptr to data buffer
  840.         mov    al,' '
  841.         mov    di,bp            ;Get start of redirect string
  842.         dec    si
  843. erase_1:
  844.         stosb
  845.         cmp    di,si
  846.         jb    erase_1
  847.         pop    di
  848.         ret
  849. erase_redirect    endp
  850.  
  851. ;-----------------------------------------------------------------------------
  852. ; IF CMD compiles an IF command.
  853. ; Entry:  SI - Pointer to character after the IF command
  854. ;      DI - Pointer to end of compiled data.
  855. ; Exit:   AL - Error code if CF set
  856. ;      CF - Set if error
  857. ;      SI,DI updated.
  858. ;-----------------------------------------------------------------------------
  859. if_cmd        proc    near
  860.         assume    cs:code,ds:code
  861.         xor    bl,bl            ;Find 1st char of next word
  862.         call    scan4char
  863.         mov    cx,si            ;Save pointer to test
  864.         mov    dx,di
  865.         mov    bp,0            ;Clear 'NOT' flag
  866. ;
  867. ;See if NOT prefix is used in test
  868. ;
  869.         lodsw                ;Get 1st two chars of test
  870.         or    ax,2020h
  871.         cmp    ax,'on'                 ;See if 'no'
  872.         jne    if_cmd_chk_cmp
  873.         lodsw                ;Get 2nd and 3rd characters
  874.         or    al,20h            ;Convert 3rd char to lower
  875.         cmp    al,'t'                  ;  case.   See if last char is
  876.         jne    if_cmd_chk_cmp         ;  't' followed by s space
  877.         cmp    ah,' '
  878.         ja    if_cmd_chk_cmp 
  879.         inc    bp
  880.         xor    bl,bl            ;Find next word
  881.         call    scan4char
  882.         mov    cx,si
  883. ;
  884. ;Test for string compare by looking for == signs.
  885. ;
  886. if_cmd_chk_cmp:
  887.         mov    si,cx            ;Restore pointer to condition
  888.         mov    bl,3            ;Find next space or equal sign
  889.         call    scan4char
  890.         jc    if_syntax_jmp
  891.         xor    bl,bl
  892.         call    scan4char        ;Find next word
  893.         cmp    word ptr [si],"=="    ;See if string compare        
  894.         je     if_cmd_cmp1        ;No, check other tests
  895.         jmp    if_cmd_chk_errlev
  896. if_cmd_cmp1:
  897.         inc    si            ;Move SI past equals signs
  898.         inc    si
  899.         xor    bl,bl            ;Find second string
  900.         call    scan4char
  901.         jnc    if_cmd_cmp2
  902. if_syntax_jmp:
  903.         jmp    if_syntax
  904. if_cmd_cmp2:
  905.         push    si            ;Save pointer to 2nd string
  906.         mov    si,cx            ;Restore ptr to 1st string
  907.         push    di            ;Save ptr to size byte
  908.         inc    di
  909.         mov    dx,di            ;Save ptr to start of string
  910.         sub    dx,databuff_start
  911.         mov    ah,2            ;Copy only one word
  912.         call    copy_string        ;Load string into data space
  913.         xor    al,al
  914.         stosb
  915.         or    bx,bx            ;See if translation is needed
  916.         pop    bx            ;Restore pointer to size byte
  917.         mov    [bx],cl         ;Save length of string
  918.         mov    cl,1            ;Assume LEA parameter call
  919.         je    if_cmd_03
  920.  
  921.         mov    bx,offset procstr_next    ;Append translate string
  922.         call    include_code        ;  routine to code.
  923.         mov    bx,offset prs2_buff_ptr - offset data_start
  924.         mov    cx,0021h        ;Indicate parameter type
  925.         call    inline_code        ;Insert translate code.
  926.         mov    dx,bx            ;Copy ptr to buffer.
  927.         mov    cx,2            ;Use MOV parameter type
  928. if_cmd_03:
  929.         pop    si            ;Restore ptr to 2nd string
  930.         push    dx            ;Save pointer to 1st string
  931.         push    cx            ;Save parameter type
  932. if_cmd_04:
  933.         push    di            ;Save ptr to size byte
  934.         inc    di
  935.         mov    dx,di            ;Save ptr to start of string
  936.         sub    dx,databuff_start
  937.         mov    ah,2
  938.         call    copy_string        ;Load string into data space
  939.         xor    al,al
  940.         stosb
  941.         or    bx,bx            ;See if translation is needed
  942.         pop    bx
  943.         mov    [bx],cl         ;Save length of string
  944.         mov    cx,10h            ;Set parameter type
  945.         je    if_cmd_06
  946.  
  947.         mov    bx,offset procstr_next    ;Append translate string
  948.         call    include_code        ;  routine to code.
  949.         mov    bx,offset prse_buff_ptr - offset data_start
  950.         mov    cx,0021h        ;Indicate parameter type
  951.         call    inline_code        ;Insert translate code.
  952.         mov    dx,bx            ;Copy ptr to buffer.
  953.         mov    cx,20h            ;Use proper parameter type
  954. if_cmd_06:
  955.         mov    bx,offset ifequal_next    ;Append comparison code
  956.         call    include_code
  957.         pop    bx            ;Restore param 1 type
  958.         and    bl,0fh
  959.         or    cl,bl            ;Combine parameter types
  960.         mov    bx,dx            ;Move parameter 2
  961.         pop    dx            ;Restore parameter 1
  962.         call    inline_code        ;Add call to string compare
  963.         jmp    if_cmd_10
  964. if_syntax:
  965.         mov    dx,offset errmsg6    ;Syntax error.
  966.         stc
  967.         jmp    if_exit
  968. ;
  969. ;See if ERRORLEVEL test.
  970. ;
  971. if_cmd_chk_errlev:
  972.         mov    si,cx            ;Restore pointer to 1st string
  973.         mov     bx,cx            ;Save pointer to 1st string
  974.         mov    di,offset ifstr1    ;See if ERRORLEVEL test
  975.         call    capsalpha
  976.         cmp    cx,10
  977.         jne    if_cmd_2
  978.         repe    cmpsb            ;Compare strings
  979.         jne    if_cmd_2
  980.         mov    bx,offset iferrlev_next ;Save offset of errlev code
  981.         push    bx            ;  on stack.  Use exist code
  982.          xor    bl,bl
  983.         call    scan4char        ;Scan to next word.
  984.         cmp    byte ptr [si],'='
  985.         jne    if_cmd_21
  986.         inc    si
  987.          xor    bl,bl
  988.         call    scan4char        ;Scan to next word.
  989.         jmp    short if_cmd_21     ;  to append error code.
  990. ;
  991. ;See if EXIST test.
  992. ;
  993. if_cmd_2:
  994.         mov    si,bx            ;Restore pointer to 1st string
  995.         mov    di,offset ifstr2    ;See if EXIST test
  996.         cmp    cx,5            ;Check length of string
  997.         jne    if_syntax
  998.         repe    cmpsb            ;Compare strings
  999.         jne    if_syntax
  1000.         mov    bx,offset ifexist_next    ;Save test existance code off
  1001.         push    bx
  1002.          xor    bl,bl
  1003.         call    scan4char        ;Scan to next word.
  1004. if_cmd_21:
  1005.         mov    di,dx            ;Restore data pointer
  1006.         sub    dx,databuff_start
  1007.         mov    ah,2
  1008.         call    copy_string
  1009.         xor    al,al            ;Terminate string with zero.
  1010.         stosb
  1011.         mov    cl,21h            ;Set parameter type
  1012.         or    bx,bx            ;See if translation is needed
  1013.         je    if_cmd_3
  1014.  
  1015.         mov    bx,offset procstr_next    ;Append translate string
  1016.         call    include_code        ;  routine to code.
  1017.         mov    bx,offset prse_buff_ptr - offset data_start
  1018.         mov    cx,0021h        ;Indicate parameter type
  1019.         call    inline_code        ;Insert translate code.
  1020.         mov    dx,bx            ;Copy ptr to buffer.
  1021.         mov    cl,22h            ;Use proper parameter type
  1022. if_cmd_3:
  1023.         pop    bx            ;Restore test code offset
  1024.         call    include_code
  1025.         mov    bx,offset prs2_buff_ptr - offset data_start
  1026.         call    inline_code        ;Insert exist test call
  1027. if_cmd_10:
  1028.         mov    cx,200h         ;Include Jump if carry opcode
  1029.         or    bp,bp
  1030.         je    if_cmd_12
  1031.         mov    cx,300h         ;Change to Jump if not carry
  1032. if_cmd_12:
  1033.         call    inline_code
  1034.         push    ax            ;Save address of jmp to modify
  1035.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1036. ;
  1037. ;Compile the remainder of the line as if it were a normal statment.
  1038. ;
  1039.         xor    bl,bl            ;Scan for next word
  1040.         call    scan4char
  1041.         call    parse            ;Compile remainder of line.
  1042.  
  1043.         pop    cx            ;Compute the difference for the
  1044.         pop    bx            ;  jmp opcode.
  1045.         jc    if_exit         ;If error during parse, exit.
  1046.         push    es
  1047.         mov    ax,word ptr codebuff_ptr
  1048.         mov    es,word ptr codebuff_ptr[2]
  1049.         sub    ax,cx
  1050.         mov    es:[bx],ax        ;Save jmp offset
  1051.         pop    es
  1052.         clc
  1053. if_exit:
  1054.         ret
  1055. if_cmd        endp
  1056.  
  1057. ;-----------------------------------------------------------------------------
  1058. ; FOR CMD compiles an FOR command.
  1059. ; Entry:  SI - Pointer to character after the FOR command
  1060. ;      DI - Pointer to end of compiled data.
  1061. ; Exit:   AL - Error code if CF set
  1062. ;      CF - Set if error
  1063. ;      SI,DI updated.
  1064. ;-----------------------------------------------------------------------------
  1065. for_cmd     proc    near
  1066.         assume    cs:code,ds:code    
  1067.         cmp    for_active_flag,0        
  1068.         je    for_cmd_0
  1069.         mov    dx,offset errmsg11    ;No nested FOR loops
  1070.         stc
  1071.         jmp    for_exit
  1072. for_cmd_0:
  1073.         mov    goto_active,0        ;Clear goto detect flag
  1074.         inc    for_active_flag
  1075.         xor    bl,bl            ;Find 1st char of next word
  1076.         call    scan4char
  1077.         jc    jmp_for_syntax
  1078.         mov    bp,si            ;Save pointer to loop variable
  1079.         mov    dx,di
  1080.         sub    dx,word ptr databuff_start
  1081. ;
  1082. ;Copy the set data to the com file data area.  As always, if environment
  1083. ;variables or command line parameters are in the data, insert a call to
  1084. ;the translate routine before calling the for loop routine.
  1085. ;
  1086. for_cmd_1:
  1087.         lodsb                ;Scan until '(' is found
  1088.         cmp    al,13            ;  indicating the start of the
  1089.         jne    for_cmd_2        ;  data set.
  1090. jmp_for_syntax:
  1091.         jmp    for_syntax
  1092. for_cmd_2:
  1093.         cmp    al,'('
  1094.         jne    for_cmd_1
  1095.         mov    ah,3            ;Copy until ')' found.
  1096.         call    copy_string
  1097.         xor    al,al            ;Terminate string with zero.
  1098.         stosb
  1099.         mov    cx,11h
  1100.         or    bx,bx
  1101.         je    for_cmd_3
  1102.  
  1103.         mov    bx,offset procstr_next    ;Append translate string
  1104.         call    include_code        ;  routine to code.
  1105.         mov    bx,offset for_buff_ptr - offset data_start
  1106.         mov    cx,0021h        ;Indicate parameter type
  1107.         call    inline_code        ;Insert translate code.
  1108.         mov    dx,bx            ;Copy ptr to buffer.
  1109.         mov    cl,12h            ;Use proper parameter type
  1110. for_cmd_3:
  1111.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1112.         mov    bx,offset forloop_next
  1113.         call    include_code
  1114.         mov    bx,di            ;Initialize for loop data
  1115.         sub    bx,databuff_start    ;  structure.
  1116.         mov    word ptr [di],0
  1117.         inc    di
  1118.         inc    di
  1119.         call    inline_code        ;Insert call to loop code.
  1120.         mov    cx,200h         ;Include Jump if carry opcode
  1121.         call    inline_code
  1122.         push    ax            ;Save address of jmp to modify
  1123.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1124.  
  1125. ;
  1126. ;Scan the remainder of the line. Replace all instances of the loop variable
  1127. ;with a special code that the run time translate routine understands.
  1128. ;
  1129.         xor    bl,bl            ;Find DO
  1130.         call    scan4char
  1131.         jc    for_syntax_1
  1132.         push    si
  1133.         lodsw                ;Confirm DO exists
  1134.         and    ax,0dfdfh        ;Convert to upper case
  1135.         cmp    ax,"OD"
  1136.         pop    si
  1137.         jne    for_syntax_1
  1138.         mov    bl,1            ;Find end of 'DO'
  1139.         call    scan4char
  1140.         jc    for_syntax_1
  1141.         xor    bl,bl            ;Find start of loop command.
  1142.         call    scan4char
  1143.         jc    for_syntax_1
  1144.         push    si            ;Save pointer to command.
  1145.         push    di            ;Save data buffer pointer.
  1146.         mov    di,si
  1147.         mov    bl,2            ;Find the end of the line.
  1148.         call    scan4char
  1149.         mov    dx,si            ;Save pointer to end of line
  1150. for_cmd_4:
  1151.         mov    si,bp            ;Get ptr to loop variable.
  1152.         mov    cx,3            ;Scan the remainder of the
  1153.         repe    cmpsb            ;  line for the loop variable.
  1154.         jne    for_cmd_5        ;  When found, replace with
  1155.         dec    di            ;  % followed by 7f7fh. This
  1156.         dec    di            ;  flag tells the runtime
  1157.         mov    ax,7f7fh        ;  xlate routine to sub in
  1158.         stosw                ;  the loop string.
  1159. for_cmd_5:
  1160.         cmp    di,dx            ;See if at the end of the line.
  1161.         jb    for_cmd_4
  1162.         pop    di            ;Restore data buffer ptr
  1163.         pop    si            ;Restore ptr to command.
  1164. ;
  1165. ;Compile the remainder of the line as if it were a normal statment.
  1166. ;
  1167.         call    parse            ;Compile remainder of line.
  1168.  
  1169.         pop    cx            ;Get code ptr after loop code
  1170.         pop    bx            ;Get addr of JC
  1171.         pop    ax            ;Get code ptr to loop code
  1172.         jc    for_exit1
  1173.         mov    dx,cx            ;DX may have had an error msg
  1174.  
  1175.         sub    ax,word ptr codebuff_ptr ;Compute displacment from END
  1176.         sub    ax,3             ;  of JMP opcode.
  1177.         mov    cx,400h         ;Insert JMP opcode after code
  1178.         call    inline_code        ;  for statments inside FOR
  1179.         mov    ax,word ptr codebuff_ptr;  loop.
  1180.         sub    ax,dx
  1181.         push    es
  1182.         mov    es,word ptr codebuff_ptr[2]
  1183.         mov    es:[bx],ax
  1184.         pop    es
  1185. ;
  1186. ; If goto parsed during FOR, place jump for goto after FOR loop
  1187. ;
  1188.         cmp    goto_active,0
  1189.         je     for_exit
  1190.         mov    dx,goto_data_ptr
  1191.         mov    bx,offset gotodly_next    ;Append goto delay 
  1192.         call    include_code        ;  routine to code.
  1193.         mov    cx,1
  1194.         call    inline_code        ;Add code to COM file.
  1195. for_exit:
  1196.         clc
  1197. for_exit1:
  1198.         mov    for_active_flag,0    ;Clear flag
  1199.         ret
  1200. for_syntax_1:
  1201.         add    sp,6            ;Clean off stack
  1202. for_syntax:
  1203.         mov    dx,offset errmsg6    ;Syntax error
  1204.         stc
  1205.         jmp    short for_exit1
  1206. for_cmd     endp
  1207.  
  1208. ;-----------------------------------------------------------------------------
  1209. ; GOTO CMD compiles a goto command.
  1210. ; Entry:  SI - Pointer to first character after the command.
  1211. ;      DI - Pointer to end of compiled data.
  1212. ; Exit:   AL - Error code if CF set
  1213. ;      CF - Set if error
  1214. ;      SI,DI updated.
  1215. ;-----------------------------------------------------------------------------
  1216. goto_cmd    proc    near
  1217.         assume    cs:code,ds:code
  1218.         mov    goto_active,1        ;Needed for FOR loop
  1219.         mov    bp,di            ;Save ptr to start of string.
  1220.         xor    bl,bl            ;Find the first nonspace char.
  1221.         call    scan4char
  1222.         mov    dx,offset errmsg6    ;Check for Syntax error
  1223.         jc    goto_cmd_error
  1224.         cmp    byte ptr [si],':'    ;See if leading :.  If so,
  1225.         jne    goto_c0            ;  don't include in label.
  1226.         inc    si
  1227. goto_c0:
  1228.         push    si
  1229.         xor    ax,ax
  1230.         stosw                ;Save word in case FOR loop
  1231.         xor    ah,ah            ;  delay goto.
  1232.         call    copy_string        ;Copy label to COM data.
  1233.         xor    al,al            ;Terminate label with zero
  1234.         stosb
  1235.         pop    si
  1236.         mov    dx,offset errmsg8    ;Check to see if label found.
  1237.         or    cx,cx            ;If not, error.
  1238.         je    goto_cmd_error
  1239.         cmp    for_active_flag,0    ;If in for loop, force eval
  1240.         jne    goto_c1            ;  Jmp must occur after FOR
  1241.  
  1242.         or    bx,bx            ;See if env var or cmd line
  1243.         je    goto_c2         ;  parms.  If not hard code jmp
  1244. goto_c1:
  1245.         mov    bx,offset procstr_next    ;Get offset of translate
  1246.         call    include_code        ;  routine. Include if needed.
  1247.  
  1248.         mov    dx,bp            ;Get pointer to label.
  1249.         sub    dx,databuff_start    ;Compute offset.
  1250.         mov    goto_data_ptr,dx    ;Save offset in case FOR loop
  1251.         add    dx,2            ;Move past word ptr
  1252.         mov    bx,offset prse_buff_ptr - offset data_start
  1253.         mov    cx,0021h        ;Indicate parameter type
  1254.         call    inline_code        ;Insert translate code.
  1255.         mov    dx,bx
  1256.         mov    cx,32h            ;Use proper parameter type
  1257.         mov    bx,offset goto_next    ;Append goto string
  1258.         call    include_code        ;  routine to code.
  1259.         xor    bx,bx
  1260.         cmp    for_active_flag,0    ;If in FOR loop delay goto.
  1261.         je    goto_c11        ;  Pass ptr to word to save
  1262.         mov    bx,goto_data_ptr    ;  destination address.
  1263. goto_c11:
  1264.         call    inline_code        ;Add code to COM file.
  1265.         jmp    goto_cmd_exit
  1266. ;
  1267. ;Since label doesn't use env vars or cmd line params, hard code JMP.
  1268. ;
  1269. goto_c2:
  1270.         mov    di,bp            ;Reset data ptr to ignore label
  1271.         call    getlabel        ;See if label in list.
  1272.         mov    ax,bx            ;Copy pointer to label pointer
  1273.         add    ax,2            ;  to code.
  1274.         sub    ax,databuff_start    ;Compute offset of pointer
  1275.         mov    cx,100h         ;Insert JMP opcode.
  1276.         call    inline_code
  1277. goto_cmd_exit:
  1278.         mov    bl,2
  1279.         call    scan4char        ;Scan to the end of the line.
  1280.         clc
  1281. goto_cmd_exit1: ret
  1282. goto_cmd_error:
  1283.         stc
  1284.         jmp    short goto_cmd_exit1
  1285. goto_cmd       endp
  1286.  
  1287. ;-----------------------------------------------------------------------------
  1288. ; LABEL CMD processes a label found in the bat file.
  1289. ; Entry:  SI - Pointer to first character of the label
  1290. ;      DI - Pointer to end of compiled data.
  1291. ; Exit:   AL - Error code if CF set
  1292. ;      CF - Set if error
  1293. ;      SI,DI updated.
  1294. ;-----------------------------------------------------------------------------
  1295. label_cmd    proc    near
  1296.         assume    cs:code,ds:code
  1297.         inc    si            ;Move past ':'
  1298.         call    getlabel
  1299.         cmp    word ptr [bx+2],-1    ;See if list entry initialized
  1300.         jne    label_error        ;  if so error.
  1301.         mov    ax,word ptr codebuff_ptr
  1302.         mov    [bx+2],ax        ;Save code ptr in COM data
  1303.         mov    bl,2
  1304.         call    scan4char        ;Scan to the end of the line.
  1305.         clc
  1306. label_exit:
  1307.         ret
  1308. label_error:
  1309.         mov    dx,offset errmsg8    ;Two identical labels
  1310.         stc
  1311.         jmp    short label_exit
  1312. label_cmd    endp
  1313.  
  1314. ;-----------------------------------------------------------------------------
  1315. ; GETLABEL searches the label list in the data area.  If a matching label entry
  1316. ;   is found it is returned, if not a label entry is created.
  1317. ; Entry:  SI - Pointer to first character of the label
  1318. ;      DI - Pointer to end of compiled data.
  1319. ; Exit:   BX - Points to label entry.
  1320. ;      SI,DI updated.
  1321. ;-----------------------------------------------------------------------------
  1322. getlabel    proc    near
  1323.         assume    cs:code,ds:code
  1324.         call    capsword        ;Convert to caps & get length.
  1325.         cmp    cx,8            ;Max length of a label 8
  1326.         jbe    getlabel_1        ;  characters to be consistant
  1327.         mov    cx,8            ;  with DOS.
  1328. getlabel_1:
  1329.         mov    bp,di            ;Save data ptr
  1330.         mov    di,offset firstlabel    ;Get ptr to the 1st label
  1331.         mov    bx,di
  1332.         cmp    word ptr [di],-1    ;See if any labels defined.
  1333.         je    getlabel_2        ;No, skip label list search.
  1334.  
  1335.         push    cx            ;Save label size
  1336.         add    bx,[bx]         ;Point to first label
  1337.         call    lblsrch_code        ;Search label list.
  1338.         pop    cx
  1339.         mov    di,bp            ;Create label entry.
  1340.         jnc    getlabel_exit
  1341. getlabel_2:
  1342.         mov    di,bp            ;Create label entry.
  1343.         mov    ax,-1
  1344.         stosw                ;Clear end of list tag
  1345.         stosw                ;Indicate unitialized label
  1346.         mov    al,cl
  1347.         stosb                ;Save length of label
  1348.         rep    movsb            ;Copy label into data buffer
  1349.         mov    ax,bp
  1350.         sub    ax,bx            ;Compute offset to new label
  1351.         mov    [bx],ax         ;Load offset in prev. label
  1352.         mov    bx,bp            ;Get start of label entry
  1353. getlabel_exit:
  1354.         clc
  1355.         ret
  1356. getlabel    endp
  1357.  
  1358. ;-----------------------------------------------------------------------------
  1359. ; EXTERNAL CMD compiles a routine to exexute a program.
  1360. ; Entry:  SI - Pointer to character after the command
  1361. ;      DI - Pointer to end of compiled data.
  1362. ; Exit:   AL - Error code if CF set
  1363. ;      CF - Set if error
  1364. ;      SI,DI updated.
  1365. ;-----------------------------------------------------------------------------
  1366. external_cmd    proc    near
  1367.         assume    cs:code,ds:code
  1368.         mov    dx,di            ;Save ptr to filename
  1369.         sub    dx,databuff_start    ;Compute offset.
  1370.         mov    ah,1
  1371.         call    copy_string        ;Copy filename to COM data.
  1372.         mov    temp1,bx        ;Save translate flag
  1373.         dec    si            ;Back up one char
  1374.         xor    al,al            ;Terminate filename with zero
  1375.         stosb
  1376.         inc    di
  1377.         push    di            ;Save ptr to command line tail
  1378.         xor    ah,ah
  1379.         call    copy_string        ;Copy command line tail.
  1380.         mov    ax,000dh        ;Append CR and zero
  1381.         stosw
  1382.         pop    bp            ;Save length of cmd line tail.
  1383.         inc    cl            ;  Adjust for the CR since 
  1384.         mov    [bp-1],cl        ;  ProcStr will add CR to the
  1385.         sub    bp,databuff_start    ;  count.  Exec prog fixes 
  1386.         mov    cx,11h            ;  this at run time.
  1387.         or    bx,bx            ;See if translation code needed
  1388.         je    externalcmd_1
  1389. ;
  1390. ;See if we need translation for command line tail.
  1391. ;
  1392.         push    dx
  1393.         mov    dx,bp            ;Get pointer to cmd line tail
  1394.         mov    bx,offset procstr_next    ;Get offset of translate
  1395.         call    include_code        ;  routine.
  1396.         mov    bx,offset prse_buff_ptr - offset data_start
  1397.         mov    cx,21h            ;Indicate parameter type
  1398.         call    inline_code        ;Insert translate code.
  1399.         mov    cx,21h            ;Use proper parameter type
  1400.         mov    bp,bx
  1401.         pop    dx
  1402. externalcmd_1:
  1403. ;
  1404. ;See if we need translation for param.
  1405. ;
  1406.         mov    ax,temp1        ;Get translate flag for cmd
  1407.         or    ax,ax            ;See if extern cmd needs
  1408.         je    externalcmd_2        ;  translation.
  1409.         mov    bx,offset procstr_next    ;Get offset of translate
  1410.         call    include_code        ;  routine.
  1411.         mov    bx,offset prs2_buff_ptr - offset data_start
  1412.         push    cx
  1413.         mov    cx,21h            ;Indicate parameter type
  1414.         call    inline_code        ;Insert translate code.        
  1415.         pop    cx
  1416.         and    cl,0f0h            ;Use proper parameter type
  1417.         or    cl,02h            ;  retain the prev param type
  1418.         mov    dx,bx            ;  for cmd line tail.
  1419. externalcmd_2:
  1420.         mov    bx,offset external_next ;Append prog launch code
  1421.         call    include_code
  1422.         mov    bx,bp            ;Get ptr to filename
  1423.         call    inline_code        ;Add code to COM file.
  1424.         clc
  1425.         ret
  1426. external_cmd    endp
  1427.  
  1428. ;-----------------------------------------------------------------------------
  1429. ; INTERNAL CMD compiles a command internal to command.com
  1430. ; Entry:  SI - Pointer to character after the command
  1431. ;      DI - Pointer to end of compiled data.
  1432. ; Exit:   AL - Error code if CF set
  1433. ;      CF - Set if error
  1434. ;      SI,DI updated.
  1435. ;-----------------------------------------------------------------------------
  1436. internal_cmd    proc    near
  1437.         assume    cs:code,ds:code
  1438.         inc    di            ;Make room for string size.
  1439.         push    di            ;Save ptr to internal command.
  1440.         push    si
  1441.         mov    si,offset internal_cmdsw
  1442.         movsw                ;Copy /C switch to tell
  1443.         movsb                ;  COMMAND.COM to execute and
  1444.         pop    si            ;  terminate.
  1445.         xor    ah,ah
  1446.         call    copy_string        ;Copy internal command
  1447.         mov    ax,000dh        ;Append CR and zero
  1448.         stosw
  1449.         pop    bp
  1450.         add    cl,3            ;Add length of /c switch
  1451.         mov    [bp-1],cl        ;Save length of command line
  1452.  
  1453.         mov    dx,bp            ;Get pointer to internal cmd
  1454.         sub    dx,databuff_start    ;Compute offset.
  1455.         mov    cx,1
  1456.         or    bx,bx            ;See if translation code needed
  1457.         je    internalcmd_1
  1458.  
  1459.         mov    bx,offset procstr_next    ;Get offset of translate
  1460.         call    include_code        ;  routine.
  1461.         mov    bx,offset prse_buff_ptr - offset data_start
  1462.         mov    cx,0021h        ;Indicate parameter type
  1463.         call    inline_code        ;Insert translate code.
  1464.         mov    cx,2            ;Use proper parameter type
  1465.         mov    dx,bx            ;Get input from str1 buffer
  1466. internalcmd_1:
  1467.         mov    bx,offset intcmd_next    ;Append internal cmd routine
  1468.         call    include_code        ;  to code.
  1469.         call    inline_code        ;Add code to COM file.
  1470.         clc
  1471.         ret
  1472. internal_cmd    endp
  1473.  
  1474. ;-----------------------------------------------------------------------------
  1475. ; PATH CMD compiles a path command
  1476. ; Entry:  Same as SET command
  1477. ;-----------------------------------------------------------------------------
  1478. path_cmd     proc    near
  1479.         assume    cs:code,ds:code
  1480.         mov    bp,2
  1481.         push    si
  1482.         add    si,4            ;Move past path cmd        
  1483.         xor    bx,bx            ;Find the first nonspace char.
  1484.         call    scan4char        ;If no characters, set flag
  1485.         pop    si
  1486.         jnc    set_entry1        ;  to print path string.
  1487.         mov    bp,3
  1488.         jmp    short set_entry1
  1489. path_cmd     endp
  1490.  
  1491. ;-----------------------------------------------------------------------------
  1492. ; PROMPT CMD compiles a path command
  1493. ; Entry:  Same as SET command
  1494. ;-----------------------------------------------------------------------------
  1495. prompt_cmd     proc    near
  1496.         assume    cs:code,ds:code
  1497.         mov    bp,1
  1498.         jmp    short set_entry1
  1499. prompt_cmd     endp
  1500.  
  1501. ;-----------------------------------------------------------------------------
  1502. ; SET CMD compiles a command to change variables in the environment
  1503. ; Entry:  SI - Pointer to character after the command
  1504. ;      DI - Pointer to end of compiled data.
  1505. ; Exit:   CF - Set if error
  1506. ;      DX - Offset to error message if CF set.
  1507. ;      SI,DI updated.
  1508. ;-----------------------------------------------------------------------------
  1509. set_cmd     proc    near
  1510.         assume    cs:code,ds:code
  1511.         mov    bp,0            ;Assume not PATH or PROMPT    
  1512. set_entry1:
  1513.         push    bp
  1514.         xor    bx,bx            ;Find the first nonspace char.
  1515.         call    scan4char
  1516.         mov    dx,di            ;Save ptr to set command.
  1517.         jc    setcmd_0
  1518.         xor    ah,ah
  1519.         call    copy_string        ;Copy string to COM data
  1520. setcmd_0:
  1521.         xor    al,al            ;Append zero
  1522.         stosb
  1523.         sub    dx,databuff_start    ;Compute offset of data.
  1524.         mov    cx,31h
  1525.         or    bx,bx            ;See if translation code needed
  1526.         je    setcmd_1
  1527.  
  1528.         mov    bx,offset procstr_next    ;Get offset of translate
  1529.         call    include_code        ;  routine.
  1530.         mov    bx,offset prse_buff_ptr - offset data_start
  1531.         mov    cx,21h            ;Indicate parameter type
  1532.         call    inline_code        ;Insert translate code.
  1533.         mov    cx,32h            ;Use proper parameter type
  1534.         mov    dx,bx            ;Get input from str1 buffer
  1535. setcmd_1:
  1536.         mov    bx,offset setenv_next    ;Append set routine to code.
  1537.         call    include_code
  1538.         pop    bx            ;Get PATH/PROMPT flag
  1539.         call    inline_code        ;Add code to COM file.
  1540.         clc
  1541.         ret
  1542. set_cmd     endp
  1543.  
  1544. ;-----------------------------------------------------------------------------
  1545. ; ECHO CMD compiles an ECHO command.
  1546. ; Entry:  SI - Pointer to character after the ECHO command
  1547. ;      DI - Pointer to end of compiled data.
  1548. ; Exit:   AL - Error code if CF set
  1549. ;      CF - Set if error
  1550. ;      SI,DI updated.
  1551. ;-----------------------------------------------------------------------------
  1552. echo_cmd    proc    near
  1553.         assume    cs:code,ds:code
  1554.         mov    dx,si            ;Save pointer to string start
  1555.         inc    dx            ;Move pointer past 1st space
  1556.         xor    bl,bl            ;Echo can either echo a
  1557.         call    scan4char        ;  string to the keyboard or
  1558.         jc    echo_c01        ;  toggle the echo flag.
  1559.         or    al,20h            ;Check for on or off keyword
  1560.         cmp    al,"o"                  ;  to indicate what type of
  1561.         jne    echo_c0         ;  Echo this is.
  1562.         mov    ax,[si+1]        ;Get next two characters
  1563.         or    al,20h            ;Make lower case
  1564.         mov    bl,1
  1565.         cmp    al,"n"                  ;Check for echo on
  1566.         je    echo_c00
  1567.         or    ah,20h            ;Make lower case
  1568.         cmp    ax,"ff"                 ;Check for echo off
  1569.         jne    echo_c0
  1570.         dec    bl
  1571.         mov    ah,[si+3]        ;Get character past word
  1572. echo_c00:
  1573.         cmp    ah," "                  ;Make sure not just the start
  1574.         ja    echo_c0         ;  of another word.
  1575.         mov    bl,2
  1576.         call    scan4char        ;Find end of line.
  1577.         jmp    short echo_exit
  1578. ;
  1579. ;Echo ASCII line, Include code in COM file to echo string.
  1580. ;
  1581. echo_c01:
  1582.         mov    si,dx            ;Restore data pointer
  1583.         cmp    byte ptr [si-2],'.'    ;See if Echo.
  1584.         jne    echo_exit
  1585.         mov    dx,di
  1586.         jmp    short echo_c1
  1587. echo_c0:
  1588.         mov    si,dx            ;Restore data pointer
  1589.         mov    dx,di
  1590.         xor    ah,ah
  1591.         call    copy_string        ;Copy string to COM data.
  1592. echo_c1:
  1593.         mov    ax,0d0ah        ;Terminate line with CRLF
  1594.         stosw
  1595.         xor    al,al            ;Append zero byte
  1596.         stosb
  1597.         mov    cx,1            ;Append runtime routines.
  1598.         sub    dx,databuff_start
  1599.         or    bx,bx            ;Check translate flag, if set
  1600.         je    echo_c21        ;  append translate code 1st.
  1601.         mov    bx,offset procstr_next    ;Append translate string
  1602.         call    include_code        ;  routine to code.
  1603.         mov    bx,offset prse_buff_ptr - offset data_start
  1604.         mov    cx,0021h        ;Indicate parameter type
  1605.         call    inline_code        ;Insert translate code.
  1606.         mov    dx,bx
  1607.         mov    cx,2            ;Use proper parameter type
  1608. echo_c21:
  1609.         mov    bx,offset echo_msg_next ;Append echo string
  1610.         call    include_code        ;  routine to code.
  1611. echo_c3:
  1612.         call    inline_code        ;Add code to COM file.
  1613. echo_cstatus:
  1614. echo_exit:
  1615.         clc
  1616. echo_cmd_exit:
  1617.         ret
  1618. echo_cmd    endp
  1619.  
  1620. ;-----------------------------------------------------------------------------
  1621. ; PAUSE CMD compiles a PAUSE command.
  1622. ; Entry:  SI - Pointer to character after the PAUSE command
  1623. ;      DI - Pointer to end of compiled data.
  1624. ; Exit:   AL - Error code if CF set
  1625. ;      CF - Set if error
  1626. ;      SI,DI updated.
  1627. ;-----------------------------------------------------------------------------
  1628. pause_cmd    proc    near
  1629.         assume    cs:code,ds:code
  1630. ;Append routine if necessary
  1631.         mov    bx,offset pause_next     ;Append PAUSE routine if
  1632.         call    include_code         ;  necessary.
  1633.  
  1634.         mov    cx,0            ;Add inline code with 0 params
  1635.         call    inline_code        ;  to call pause routine.
  1636.  
  1637.         mov    bl,2            ;Scan to end of line
  1638.         call    scan4char
  1639.         clc
  1640. pause_cmd_exit:
  1641.         ret
  1642. pause_cmd    endp
  1643.  
  1644. ;-----------------------------------------------------------------------------
  1645. ; SHIFT CMD compiles a SHIFT command.
  1646. ; Entry:  SI - Pointer to character after the SHIFT command
  1647. ;      DI - Pointer to end of compiled data.
  1648. ; Exit:   AL - Error code if CF set
  1649. ;      CF - Set if error
  1650. ;      SI,DI updated.
  1651. ;-----------------------------------------------------------------------------
  1652. shift_cmd    proc    near
  1653.         assume    cs:code,ds:code
  1654.         mov    bx,offset shift_next     ;Append shift routine if
  1655.         call    include_code         ;  necessary.
  1656.         mov    cx,0            ;Add inline code with 0 params
  1657.         call    inline_code        ;  to call pause routine.
  1658.         mov    bl,2            ;Scan to end of line
  1659.         call    scan4char
  1660.         clc
  1661.         ret
  1662. shift_cmd    endp
  1663.  
  1664. ;-----------------------------------------------------------------------------
  1665. ; REM CMD  Processes remark lines in batch file.
  1666. ; Entry:  SI - pointer to line in BAT file
  1667. ;-----------------------------------------------------------------------------
  1668. rem_cmd     proc near
  1669.         assume    cs:code,ds:code
  1670.         dec    si            ;Back up to make sure we don't
  1671. rem_c1:     lodsb                ;  miss a carrage return.
  1672.         cmp    al,1ah            ;Loop until end of line or end
  1673.         je    rem_exit        ;  of file.
  1674.         cmp    al,13
  1675.         jne    rem_c1
  1676. rem_exit:
  1677.         clc
  1678.         ret
  1679. rem_cmd     endp
  1680.  
  1681. ;-----------------------------------------------------------------------------
  1682. ; COPY STRING copies a string to the com file data buffer.
  1683. ; Entry:  SI - Pointer to 1st character of the string.
  1684. ;      DI - Pointer to end of compiled data.
  1685. ;      AH - 0 = copy until end of line
  1686. ;           1 = copy only one word
  1687. ;           2 = copy only one word, break on /
  1688. ;           3 = copy until ')'
  1689. ; Exit:   BX - 0 if no environment variables or command line parameters.
  1690. ;      CX - Size of string.
  1691. ;      SI,DI updated.
  1692. ;-----------------------------------------------------------------------------
  1693. copy_string    proc    near
  1694.         assume    cs:code,ds:code
  1695.         push    dx
  1696.         mov    dx,di            ;Copy pointer to string
  1697.         xor    bx,bx            ;Clear param/env flag
  1698.         xor    cx,cx            ;Clear count
  1699. copystr_1:
  1700.         lodsb                ;Get byte
  1701.         cmp    al,13            ;See if carrage return
  1702.         je    copystr_exit        ;Yes, quit.
  1703.         cmp    al,1ah            ;See if EOF
  1704.         je    copystr_exit
  1705. copystr_2:
  1706.         cmp    ah,3            ;See if set copy
  1707.         jne    copystr_3        ;No, skip next test.
  1708.         cmp    al,')'                  ;See if end of set
  1709.         je    copystr_exit        ;Yes, quit.
  1710.         jmp    short copystr_4
  1711. copystr_3:
  1712.         or     ah,ah            ;See if phrase or word copy
  1713.         je     copystr_4        ;Phase, skip next test.
  1714.         cmp    al,' '                  ;See if end of word.
  1715.         jbe    copystr_exit        ;Yes, quit.
  1716.         cmp    al,'='                  ;Equal sign indicates end of
  1717.         je    copystr_exit        ;  word.
  1718.         cmp    ah,2
  1719.         je     copystr_4
  1720.         cmp    al,'/'                  ;/ indicates end of word.
  1721.         je    copystr_exit        
  1722. copystr_4:
  1723.         inc    cx
  1724.         cmp    al,'%'                  ;See if translation needed.
  1725.         jne    copystr_6
  1726.         inc    bh
  1727.         or    bl,bl            ;See if already set.
  1728.         mov    bl,0            ;Clear flag
  1729.         jne    copystr_6        ;If set, this must be the
  1730.         cmp    byte ptr [si],7fh    ;Check for For loop var. If
  1731.         jne    copystr_5        ;  found, copy it removing
  1732.         stosb                ;  the extra 7f.
  1733.         lodsb
  1734.         inc    si
  1735.         jmp    short copystr_6
  1736. copystr_5:
  1737.         cmp    byte ptr [si],'9'       ;  trailing % of an env var.
  1738.         jbe    copystr_6
  1739.         call    capsword        ;Env var, capitialize it.
  1740.         inc    bl
  1741. copystr_6:
  1742.         stosb                ;Save byte
  1743.         jmp    short copystr_1     ;Loop back.
  1744. copystr_exit:
  1745.         pop    dx
  1746.         ret
  1747. copy_string    endp
  1748.  
  1749. ;-----------------------------------------------------------------------------
  1750. ; INLINE CODE  Adds the necessary inline code to call a canned
  1751. ;        routine.
  1752. ; Entry:  AX - Offset of canned routine.
  1753. ;      CL - (low nibble) Method to pass parameter one
  1754. ;      CL - (high nibble) Method to pass parameter two
  1755. ;      CH - (low nibble) Call/Jump method
  1756. ;      DX - Parameter one
  1757. ;      BX - Parameter two
  1758. ;-----------------------------------------------------------------------------
  1759. inline_code    proc    near
  1760.         push    bp
  1761.         push    si            ;Save pointer to input buffer.
  1762.         push    di
  1763.         push    es
  1764.         les    di,codebuff_ptr     ;Point ES:DI to buffer
  1765.         mov    bp,cx
  1766.         and    cl,0fh            ;Look only at SI code nibble
  1767.         cmp    cl,1            ;Check for LEA SI
  1768.         jne    inline_1
  1769.         mov    si,offset code_leasi
  1770.         mov    [si+2],dx        ;Load paramter one
  1771.         mov    cx,code_leasi_size
  1772.         rep    movsb            ;Copy routine into COM file.
  1773.         jmp    short inline_10
  1774. inline_1:
  1775.         cmp    cl,2            ;Check for MOV SI
  1776.         jne    inline_2
  1777.         mov    si,offset code_movsi
  1778.         mov    [si+2],dx        ;Load parameter one
  1779.         mov    cx,code_movsi_size
  1780.         rep    movsb            ;Copy routine into COM file.
  1781.         jmp    short inline_10
  1782. inline_2:
  1783.         cmp    cl,3            ;Check for MOV SI Immediate
  1784.         jne    inline_10
  1785.         mov    si,offset code_movsiim
  1786.         mov    [si+1],dx        ;Load parameter one
  1787.         mov    cx,code_movsiim_size
  1788.         rep    movsb            ;Copy routine into COM file.
  1789. inline_10:
  1790.         mov    cx,bp            ;Get back code
  1791.         and    cl,0f0h
  1792.         cmp    cl,10h            ;Check for LEA DI
  1793.         jne    inline_11
  1794.         mov    si,offset code_leadi
  1795.         mov    [si+2],bx        ;Load paramter two
  1796.         mov    cx,code_leadi_size
  1797.         rep    movsb            ;Copy routine into COM file.
  1798.         jmp    short inline_13
  1799. inline_11:
  1800.         cmp    cl,20h            ;Check for MOV DI
  1801.         jne    inline_12
  1802.         mov    si,offset code_movdi
  1803.         mov    [si+2],bx        ;Load parameter two
  1804.         mov    cx,code_movdi_size
  1805.         rep    movsb            ;Copy routine into COM file.
  1806.         jmp    short inline_13
  1807. inline_12:
  1808.         cmp    cl,30h            ;Check for MOV immed DI
  1809.         jne    inline_13
  1810.         mov    si,offset code_movdiim
  1811.         mov    [si+1],bx        ;Load parameter two
  1812.         mov    cx,code_movdiim_size
  1813.         rep    movsb            ;Copy routine into COM file.
  1814. inline_13:
  1815.         mov    cx,bp
  1816.         and    ch,0fh
  1817.         jne    inline_20
  1818.         mov    si,offset code_call    ;Code to call the canned
  1819.         mov    cx,code_call_size    ;  routine.
  1820.         mov    [si+1],ax        ;Insert the destination offset.
  1821.         rep    movsb            ;Copy routine into COM file.
  1822.         jmp    short inline_30
  1823. inline_20:
  1824.         cmp    ch,01            ;Check for jmp
  1825.         jne    inline_21
  1826.         mov    si,offset code_jmp    ;Code to jmp to destination.
  1827.         mov    cx,code_jmp_size
  1828.         mov    [si+2],ax        ;Insert the destination offset.
  1829.         rep    movsb            ;Copy routine into COM file.
  1830.         jmp    short inline_30
  1831. inline_21:
  1832.         cmp    ch,02            ;Check for jc
  1833.         jne    inline_22
  1834.         mov    si,offset code_jc    ;Code to jc to destination.
  1835.         mov    cx,code_jc_size
  1836.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1837.         rep    movsb            ;Copy routine into COM file.
  1838.         jmp    short inline_30
  1839. inline_22:
  1840.         cmp    ch,03            ;Check for jnc
  1841.         jne    inline_23
  1842.         mov    si,offset code_jnc    ;Code to jnc to destination.
  1843.         mov    cx,code_jnc_size
  1844.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1845.         rep    movsb            ;Copy routine into COM file.
  1846.         jmp    short inline_30
  1847. inline_23:
  1848.         cmp    ch,04            ;Check for jmp displacment
  1849.         jne    inline_30
  1850.         mov    si,offset code_jmpdis    ;Code to jmp IP relative.
  1851.         mov    [si+1],ax
  1852.         mov    cx,code_jmpdis_size
  1853.         rep    movsb            ;Copy routine into COM file.
  1854. inline_30:
  1855.         mov    word ptr cs:codebuff_ptr,di
  1856.         pop    es
  1857.         pop    di
  1858.         pop    si
  1859.         pop    bp
  1860.         ret
  1861. inline_code    endp
  1862.  
  1863. ;-----------------------------------------------------------------------------
  1864. ; INCLUDE CODE - Appends the routine to the append list if necessary and
  1865. ;         returns the offset of the routine in the compiled program.
  1866. ; Entry:  BX - Pointer to header of canned routine to append.
  1867. ; Exit:   AX - Offset of canned routine in COM file.
  1868. ;-----------------------------------------------------------------------------
  1869. include_code    proc    near
  1870.         assume    ds:code,es:nothing
  1871.         push    cx
  1872.         push    dx
  1873.         mov    ax,[bx-4]        ;Get COM file offset
  1874.         or    ax,ax            ;If zero, routine has not
  1875.         jne    include_exit        ;  been appended.
  1876.         mov    cx,bx            ;Save pointer to new routine
  1877. ;
  1878. ;Address the prevous 'last' routine header.  Update that header, then use
  1879. ;information in that header to compute the offset of the new routine.
  1880. ;
  1881.         xchg    bx,last_routine
  1882.         mov    [bx],cx         ;Add code to chain.
  1883.         mov    ax,[bx-2]        ;Compute offset of new routine
  1884.         add    ax,[bx-4]        ;  by adding the offset of the
  1885.         sub    ax,[bx+2]        ;  prevous routine to its size.
  1886.         mov    bx,cx
  1887.  
  1888.         mov    cx,[bx+2]        ;Get number of called routines.
  1889.         add    ax,cx
  1890.         mov    [bx-4],ax        ;Set offset of code.
  1891.         jcxz    include_exit
  1892.         shr    cx,1            ;If this routine needs other
  1893.         add    bx,4            ;  routines, include them in
  1894.         push    ax            ;  the COM file.
  1895. include_1:
  1896.         push    cx
  1897.         push    bx
  1898.         mov    bx,[bx]
  1899.         call    include_code
  1900.         pop    bx
  1901.         mov    [bx],ax
  1902.         add    bx,2
  1903.         pop    cx
  1904.         loop    include_1
  1905.         pop    ax
  1906. include_exit:
  1907.         pop    dx
  1908.         pop    cx
  1909.         ret
  1910. include_code    endp
  1911. ;-----------------------------------------------------------------------------
  1912. ; PRINTMSG prints the message pointed to by DX to the screen.
  1913. ; Entry:  DX - pointer to ASCII message terminated by $
  1914. ;-----------------------------------------------------------------------------
  1915. printmsg    proc    near
  1916.         assume    ds:nothing,es:nothing
  1917.         push    ds
  1918.         push    cs
  1919.         pop    ds
  1920.         assume    ds:code
  1921.         mov    ah,9            ;Print message
  1922.         int    21h
  1923.         pop    ds
  1924.         ret
  1925. printmsg    endp
  1926.  
  1927. ;-----------------------------------------------------------------------------
  1928. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1929. ; Entry:  DX - pointer to ASCII message terminated by $
  1930. ;-----------------------------------------------------------------------------
  1931. printmsgcr    proc    near
  1932.         assume    ds:nothing,es:nothing
  1933.         push    dx
  1934.         call    printmsg
  1935.         mov    dx,offset endmsg
  1936.         call    printmsg
  1937.         pop    dx
  1938.         ret
  1939. printmsgcr    endp
  1940.  
  1941. ;-----------------------------------------------------------------------------
  1942. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  1943. ; Entry:  AX - binary number
  1944. ;-----------------------------------------------------------------------------
  1945. hex2asc     proc near
  1946.         assume    ds:nothing,es:nothing
  1947.         push    bx
  1948.         mov    cx,5            ;Allow max of five digits
  1949. hex_loop1:
  1950.         xor    dx,dx            ;Clear high word
  1951.         mov    bx,10            ;Load number base
  1952.         div    bx            ;Divide by base (10)
  1953.         add    dl,30h            ;Convert to ascii
  1954.         push    dx            ;Save digit on stack
  1955.         loop    hex_loop1
  1956.         mov    cx,5            ;Allow max of five digits
  1957.         mov    bl,"0"                  ;Set leading zero indicator
  1958. hex_loop2:
  1959.         pop    dx            ;Get digit off stack
  1960.         or    bl,dl            ;Don't print leading zeros.
  1961.         cmp    bl,"0"                  ;The first non zero will
  1962.         je    hex_1            ;  change bl to non-zero.
  1963.         mov    ah,2            ;DOS character output
  1964.         int    21h
  1965. hex_1:
  1966.         loop    hex_loop2
  1967. hex_exit:
  1968.         pop    bx
  1969.         ret
  1970. hex2asc     endp
  1971.  
  1972. ;-----------------------------------------------------------------------------
  1973. ; LOADBATFILE loads the input BAT file.
  1974. ; Entry:  DS:SI - pointer to the name of the file to open
  1975. ; Exit:      CF - clear if successful
  1976. ;
  1977. ;  Support for BAT files larger than 16 K is not currently implimented.
  1978. ;-----------------------------------------------------------------------------
  1979. loadbatfile    proc    near
  1980.         assume    cs:code,ds:code
  1981.         push    di
  1982.         push    si
  1983.         mov    bx,file_handle
  1984.         cmp    bx,-1
  1985.         jne    loadfile_3
  1986.         mov    dx,si            ;Save filename pointer
  1987.         mov    di,offset outfile_name    ;Point DI to buffer to hold
  1988.         mov    cx,8            ;  the output file name.
  1989. loadfile_1:
  1990.         lodsb                ;Copy the name until the 
  1991.         cmp    al,' '            ;  extension is reached.
  1992.         je    loadfile_2        
  1993.         cmp    al,'.'
  1994.         je     loadfile_2
  1995.         stosb
  1996.         loop    loadfile_1
  1997. loadfile_2:    
  1998.         mov    si,offset com_string    ;Append COM extension to 
  1999.         movsb                ;  output file name.
  2000.         movsw
  2001.         movsw
  2002.         mov    si,dx            ;Get back filename pointer
  2003.         mov    bl,1            ;Find end of filename
  2004.         call    scan4char
  2005.         dec    si
  2006.         mov    byte ptr [si],0     ;Make filename ASCIIZ.
  2007.         mov    ax,3d00h        ;Open file (Read only)
  2008.         int    21h
  2009.         jc    loadfile_error
  2010.         mov    bx,ax            ;Copy file handle
  2011. ;
  2012. ;Read contents into file buffer.
  2013. ;
  2014. loadfile_3:
  2015.         mov    file_handle,-1        ;Assume file completely read.
  2016.         mov    ah,3fh            ;Read input BAT file into
  2017.         mov    dx,inbuff_ptr        ;  memory above stack space
  2018.         mov    cx,inbuff_size         ;Get size of buffer
  2019.         sub    cx,4
  2020.         int    21h            
  2021.         mov    di,dx            ;Point DI to end of the file
  2022.         add    di,ax    
  2023.         cmp    ax,cx            ;Check if complete file read.
  2024.         jb     loadfile_4
  2025.         std                ;If there is more of the file
  2026.         push    dx            ;  to read, scan backwards to
  2027.         mov     dx,ax            ;  the end of the last line.
  2028.         mov    cx,ax            ;Get file length
  2029.  
  2030.         mov    al,13            ;Scan for last CR
  2031.         repne    scasb
  2032.         cld                ;Reset string flag
  2033.         add      di,3
  2034.         add    cx,3
  2035.         xchg    cx,dx            ;Compute the number of bytes
  2036.         sub    dx,cx            ;  to back up the file pointer
  2037.         mov    cx,0            ;  The filepointer is a 32
  2038.         jz    loadfile_31        ;  bit number in CX,DX.
  2039.         dec    cx
  2040. loadfile_31:
  2041.         mov    ax,4201h        ;Move file pointer backwards
  2042.         int    21h
  2043.         mov    file_handle,bx
  2044.         pop    dx
  2045. loadfile_4:
  2046.         mov    ax,1a1ah
  2047.         stosw                ;Append EOF bytes.
  2048.         stosw
  2049.  
  2050.         cmp    file_handle,-1
  2051.         jne    loadfile_exit
  2052.         mov    ah,3eh            ;Close file.
  2053.         int    21h
  2054. loadfile_exit:
  2055.         clc
  2056. loadfile_exit1:
  2057.         pop    si
  2058.         pop    di
  2059.         ret
  2060. loadfile_error:
  2061.         stc
  2062.         mov    dx,offset errmsg2    ;Bad filename specified.
  2063.         jmp    short loadfile_exit1
  2064. loadbatfile    endp
  2065.  
  2066. ;-----------------------------------------------------------------------------
  2067. ; SCAN4CHAR scans a string to find the first character.
  2068. ; Entry:  SI - pointer to ASCII string
  2069. ;      BL - 0 = find next char, 
  2070. ;              1 = find next space, 
  2071. ;              2 = find end of line,
  2072. ;              3 = find next space or =.
  2073. ; Exit:   AL - matching character
  2074. ;      SI - pointer to matching character
  2075. ;      CF - set if carriage return or EOF found
  2076. ;-----------------------------------------------------------------------------
  2077. scan4char    proc near
  2078.         assume    ds:nothing,es:nothing
  2079. scan4loop:
  2080.         lodsb
  2081.         cmp    al,13            ;Check for carriage return.
  2082.         je    scan4_eol
  2083.         cmp    al,1ah            ;Check for end of file char.
  2084.         jne    scan4_1
  2085. scan4_eol:
  2086.         stc
  2087.         jmp    short scan4_exit1
  2088. scan4_1:
  2089.         cmp    bl,3
  2090.         je    scan4_equal
  2091.         cmp    bl,1            ;Check if searching for space,
  2092.         je    scan4_space         ;  character, or end of line.
  2093.         ja    scan4loop
  2094.         cmp    al," "                  ;Check for space or other
  2095.         jbe    scan4loop        ;  'white' characters.
  2096.         jmp    short scan4_exit
  2097. scan4_equal:
  2098.         cmp    al,"="            ;Check for exit
  2099.         je    scan4_exit
  2100. scan4_space:
  2101.         cmp    al," "                  ;Check for characters.
  2102.         ja    scan4loop
  2103. scan4_exit:
  2104.         dec    si            ;Back up before character
  2105.         clc
  2106. scan4_exit1:
  2107.         ret
  2108. scan4char    endp
  2109.  
  2110. ;============================================================================
  2111. ;Routines used by compiled program.
  2112. ;============================================================================
  2113. ;!!--------------------------------------------------------------------------
  2114. ;Code fragments used to call canned routines.
  2115. ;----------------------------------------------------------------------------
  2116. code_call    proc    near
  2117.         mov    ax,1234h        ;Set address to call routine.
  2118.         call    ax            ;Call canned routine.
  2119. code_call_end    =    $
  2120. code_call    endp
  2121.  
  2122. code_jmp    proc    near
  2123.         mov    ax,[bp+1234h]        ;Set address to call routine.
  2124.         jmp    ax            ;Jump to new offset.
  2125. code_jmp_end    =    $
  2126. code_jmp    endp
  2127.  
  2128. code_jc     proc    near
  2129.         jnc    code_jc_end        ;Jump over long jmp
  2130.         jmp    initialize        ;This jmp will be modified
  2131. code_jc_end    =    $
  2132. code_jc     endp
  2133.  
  2134. code_jnc    proc    near
  2135.         jc    code_jnc_end        ;Skip over long jmp
  2136.         jmp    initialize        ;This jmp will be modified
  2137. code_jnc_end    =    $
  2138. code_jnc    endp
  2139.  
  2140. code_jmpdis    proc    near
  2141.         jmp    initialize        ;This jmp will be modified
  2142. code_jmpdis_end =    $
  2143. code_jmpdis    endp
  2144.  
  2145. code_leasi    proc    near
  2146.         lea    si,[bp+1234h]        ;Load address of data
  2147. code_leasi_end    =    $
  2148. code_leasi    endp
  2149.  
  2150. code_movsi    proc    near
  2151.         mov    si,[bp+1234h]        ;Load data
  2152. code_movsi_end    =    $
  2153. code_movsi    endp
  2154.  
  2155. code_movsiim    proc    near
  2156.         mov    si,1234h        ;Load immediate data
  2157. code_movsiim_end  =    $
  2158. code_movsiim    endp
  2159.  
  2160. code_leadi    proc    near
  2161.         lea    di,[bp+1234h]        ;Load address of data
  2162. code_leadi_end    =    $
  2163. code_leadi    endp
  2164.  
  2165. code_movdi    proc    near
  2166.         mov    di,[bp+1234h]        ;Load data
  2167. code_movdi_end    =    $
  2168. code_movdi    endp
  2169.  
  2170. code_movdiim    proc    near
  2171.         mov    di,1234h        ;Load immediate data
  2172. code_movdiim_end  =    $
  2173. code_movdiim    endp
  2174.  
  2175. ;----------------------------------------------------------------------------
  2176. ;Predefined data needed for all compiled programs.
  2177. ;----------------------------------------------------------------------------
  2178. data_start    =    $
  2179. code_start    dw    ?            ;Offset of main code routine
  2180. stack_ptr    dw    ?            ;Offset of end of code + stack
  2181. prog_segsize    dw    ?            ;Size of COM prog in paragraphs
  2182. prse_buff_ptr    dw    ?            ;Buffer for parsing strings
  2183. prs2_buff_ptr    dw    ?            ;Buffer for parsing strings
  2184. exec_buff_ptr    dw    ?            ;Buffer for exec function
  2185. for_buff_ptr    dw    ?            ;Buffer for For loop variables
  2186. floop_ptr    dw    ?            ;Pointer to for loop string
  2187. file_handle1    dw    ?            ;Saved handle of std output
  2188. file_handle2    dw    ?            ;Handle of output file
  2189. file_handle3    dw    ?            ;Saved handle of std input
  2190. file_handle4    dw    ?            ;Handle of input file
  2191. label_list_strt dw    ?            ;Offset into data of 1st label.
  2192. master_env    dw    ?            ;Segment of environment blk
  2193. version_num    dw    ?            ;DOS version number
  2194. proc_rc     db    ?            ;Return code of last program.
  2195. shift_cnt    db    ?            ;Count of shift parameter
  2196. data_end    =    $
  2197.  
  2198. ;----------------------------------------------------------------------------
  2199. ;INIT CODE Routine at the start of all compiled programs.
  2200. ;----------------------------------------------------------------------------
  2201. init_code_off    dw    100h            ;Pointer to offset in COM file
  2202. init_code_size    dw    offset init_code_end-offset init_code_start
  2203. init_code_next    dw    0            ;Ptr to next routine to append
  2204. init_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2205. init_code_start =    $
  2206.  
  2207. init_code    proc    near
  2208.         assume    cs:code,ds:code,es:code,ss:code
  2209.         cld
  2210.         mov    bp,ds:[offset data_start_ptr - offset init_code + 100h]
  2211.         mov    bp,[bp]
  2212.         mov    sp,com_stack_ptr    ;Move stack pointer
  2213.         mov    bx,com_prog_size    ;Reduce memory allocation
  2214.         mov    ah,4ah            ;Resize memory block
  2215.         int    21h
  2216.         mov    ax,ds:[2ch]        ;Get program environment seg
  2217.         mov    environment_seg,ax    ;  use unless SET cmd used.
  2218.         mov    bx,code_start_ptr    ;Get starting code offset
  2219.         jmp    bx            ;Jump to start of code.
  2220. data_start_ptr    dw    ?            ;Offset of data area.
  2221. init_code    endp
  2222. init_code_end    =    $
  2223.  
  2224. ;----------------------------------------------------------------------------
  2225. ;END CODE Routine appended at the end of all compiled programs.
  2226. ;----------------------------------------------------------------------------
  2227. end_code_off    dw    0            ;Pointer to offset in COM file
  2228. end_code_size    dw    offset end_code_end-offset end_code_start
  2229. end_code_next    dw    0            ;Ptr to next routine to append
  2230. end_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2231. end_code_start    =    $
  2232.  
  2233. end_code    proc    near
  2234.         assume    cs:code,ds:code
  2235.         mov    ax,4c00h        ;Terminate program
  2236.         int    21h
  2237. end_code    endp
  2238. end_code_end    =    $
  2239.  
  2240. ;----------------------------------------------------------------------------
  2241. ;ECHO MSG CODE Routine used print a string to the standard output device
  2242. ; Entry:  DS:SI - offset of string to print.
  2243. ;----------------------------------------------------------------------------
  2244. echo_msg_off    dw    0            ;Pointer to offset in COM file
  2245. echo_msg_size    dw    offset echo_msg_end-offset echo_msg_start
  2246. echo_msg_next    dw    0            ;Ptr to next routine to append
  2247. echo_msg_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2248. echo_msg_start    =    $
  2249.  
  2250. echo_msg_code    proc    near
  2251.         assume    cs:code,ds:code
  2252.         mov    dl,[si]         ;Get character
  2253.         inc    si
  2254.         or    dl,dl
  2255.         je    echo_msg_1
  2256.         mov    ah,2            ;Print character
  2257.         int    21h
  2258.         jmp    short echo_msg_code
  2259. echo_msg_1:
  2260.         ret
  2261. echo_msg_code    endp
  2262. echo_msg_end    =    $
  2263.  
  2264. ;----------------------------------------------------------------------------
  2265. ;ECHO STATUS CODE Routine used to report the status of the echo flag.
  2266. ; Entry:  AL - Echo flag.
  2267. ;----------------------------------------------------------------------------
  2268. echo_stat_ptr    dw    0            ;Pointer to offset in COM file
  2269. echo_stat_size    dw    offset echo_stat_end-offset echo_stat_start
  2270. echo_stat_next    dw    0            ;Ptr to next routine to append
  2271. echo_stat_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2272. echo_stat_start =    $
  2273.  
  2274. echo_stat_code    proc    near
  2275.         assume    cs:code,ds:code
  2276.         call    echo_stat_1        ;Push IP on stack
  2277. echo_msg    db    "ECHO is $"
  2278. echo_on     db    "on",10,13,"$"
  2279. echo_off    db    "off",10,13,"$"
  2280. echo_stat_1:
  2281.         pop    dx            ;Pop offset of echo message
  2282.         push    ax            ;Save status of echo flag
  2283.         mov    ah,9
  2284.         int    21h
  2285.         add    dx,offset echo_on-offset echo_msg ;Point to 'on' msg
  2286.         pop    ax
  2287.         or    al,al            ;Check status of echo flag
  2288.         je    echo_report_1
  2289.         add    dx,offset echo_off-offset echo_on ;Point to 'off' msg
  2290.         add    dx,5            ;Point to off message.
  2291. echo_report_1:
  2292.         mov    ah,9            ;Print last part of echo stat
  2293.         int    21h
  2294.         ret
  2295. echo_stat_code    endp
  2296. echo_stat_end    =    $
  2297.  
  2298. ;----------------------------------------------------------------------------
  2299. ;PAUSE CODE Routine used pause execution of the COM file.
  2300. ;----------------------------------------------------------------------------
  2301. pause_ptr    dw    0            ;Pointer to offset in COM file
  2302. pause_size    dw    offset pause_end-offset pause_start
  2303. pause_next    dw    0            ;Ptr to next routine to append
  2304. pause_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2305. pause_start    =    $
  2306.  
  2307. pause_code    proc    near
  2308.         assume    cs:code,ds:code
  2309.         call    pause_1     ;Push IP on stack
  2310. pause_msg    db    "Strike any key when ready...",13,10,"$"
  2311. pause_1:
  2312.         pop    dx            ;Pop offset of message
  2313.         mov    ah,9            ;Print message.
  2314.         int    21h
  2315.  
  2316.         mov    ah,7            ;Keyboard unfiltered input
  2317.         int    21h            ;  without echo.
  2318.         ret
  2319. pause_code    endp
  2320. pause_end    =    $
  2321.  
  2322. ;----------------------------------------------------------------------------
  2323. ;SHIFT CODE Routine used shift the input parameters by one.
  2324. ;----------------------------------------------------------------------------
  2325. shift_ptr    dw    0            ;Pointer to offset in COM file
  2326. shift_size    dw    offset shift_end-offset shift_start
  2327. shift_next    dw    0            ;Ptr to next routine to append
  2328. shift_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2329. shift_start    =    $
  2330.  
  2331. shift_code    proc    near
  2332.         assume    cs:code,ds:code
  2333.         inc    byte ptr shift_count     ;Inc shift count.
  2334.         ret
  2335. shift_code    endp
  2336. shift_end    =    $
  2337.  
  2338. ;-----------------------------------------------------------------------------
  2339. ; SCAN_CHAR scans a string to find the first character.
  2340. ; Entry:  SI - pointer to ASCII string
  2341. ;      DL - 0 = find next char, 1 = find next space
  2342. ;      CX - file length
  2343. ; Exit:   AL - first nonspace character
  2344. ;      CF - set if carriage return found
  2345. ;-----------------------------------------------------------------------------
  2346. scan4_off    dw    0            ;Pointer to offset in COM file
  2347. scan4_size    dw    offset scan4_end - offset scan4_start
  2348. scan4_next    dw    0            ;Ptr to next routine to append
  2349. scan4_lnks    dw    0
  2350. scan4_start    =    $
  2351.  
  2352. scan_char    proc near
  2353.         assume    ds:nothing,es:nothing
  2354. scan_loop:
  2355.         lodsb
  2356.         cmp    al,9            ;See if char is tab
  2357.         je    scan_space        ;If before, end of line
  2358.         cmp    al," "                  ;See if char is space.
  2359.         jb    scan_eol        ;If before, end of line
  2360.         je    scan_space
  2361.         or    dl,dl            ;Not space, if looking
  2362.         jne    scan_loop        ;  for space continue.
  2363.         jmp    short scan_exit
  2364. scan_space:
  2365.         or    dl,dl            ;Space found, see if looking
  2366.         je    scan_loop        ;  for one.
  2367. scan_exit:
  2368.         clc
  2369.         ret
  2370. scan_eol:
  2371.         stc
  2372.         ret
  2373. scan_char    endp
  2374. scan4_end    =    $
  2375.  
  2376. ;-----------------------------------------------------------------------------
  2377. ; GETMEMBER  returns a pointer to the Nth word in a line.
  2378. ; Entry:     SI - pointer to line of words
  2379. ;         DH - number of the word to return
  2380. ; Exit:      SI - pointer to word
  2381. ;         CF - Set if word not in line.
  2382. ;-----------------------------------------------------------------------------
  2383. getmember_scan4 equ    [bx-6]
  2384. getmember_off    dw    0            ;Pointer to offset in COM file
  2385. getmember_size    dw    offset getmember_end - offset getmember_start
  2386. getmember_next    dw    0            ;Ptr to next routine to append
  2387. getmember_lnks    dw    2            ;Bytes in the dependancy header
  2388. getmember_start =    $
  2389.         dw    offset scan4_next    ;Offset of called routine.
  2390.  
  2391. getmember    proc    near
  2392.         assume    cs:code,ds:code,es:code,ss:code
  2393.         push    bx
  2394.         call    getmember_0
  2395. getmember_0:
  2396.         pop    bx
  2397. getmember_1:
  2398.         xor    dl,dl
  2399.         call    getmember_scan4     ;Find next word
  2400.         jc    getmember_notfound
  2401.         dec    dh            ;Dec parameter count
  2402.         jle    getmember_2
  2403.         inc    dl
  2404.         call    getmember_scan4     ;Find next space
  2405.         jc    getmember_exit
  2406.         jmp    short getmember_1    ;If not done, loop back.
  2407. getmember_2:
  2408.         dec    si            ;Backup to 1st char in word.
  2409.         clc
  2410. getmember_exit:
  2411.         pop    bx
  2412.         ret
  2413. getmember_notfound:
  2414.         stc
  2415.         jmp    short getmember_exit
  2416. getmember    endp
  2417. getmember_end    =    $
  2418.  
  2419. ;-----------------------------------------------------------------------------
  2420. ; PROCSTRING processes a string to convert any environment variables or
  2421. ;         command line variables.
  2422. ; Entry:  DS:SI - ASCIIZ string to process
  2423. ;      ES:DI - pointer to output buffer.
  2424. ; Exit:   DS:SI - pointer to beginning of new ASCIIZ string.
  2425. ;     [SI-1] - Length of new string.
  2426. ;-----------------------------------------------------------------------------
  2427. procstr_cmdl    equ    [bx-8]
  2428. procstr_env    equ    [bx-6]
  2429. procstr_off    dw    0            ;Pointer to offset in COM file
  2430. procstr_size    dw    offset procstr_end - offset procstr_start
  2431. procstr_next    dw    0            ;Ptr to next routine to append
  2432. procstr_lnks    dw    4            ;Bytes in the dependancy header
  2433.  
  2434. procstr_start    =    $
  2435.         dw    offset subparm_next    ;Offset of called routines.
  2436.         dw    offset subenv_next
  2437.  
  2438. procstr_code    proc    near
  2439.         assume    cs:code,ds:code,es:code
  2440.         push    bx
  2441.         call    procstr_0
  2442. procstr_0:
  2443.         pop    bx
  2444.         push    di
  2445.         push    si
  2446.         mov    ah,BUFF_SIZE        ;Set size of buffer
  2447. procstr_1:
  2448.         lodsb                ;Get byte from string
  2449.         or    al,al            ;Check for end of string
  2450.         je    procstr_exit
  2451.         cmp    al,"%"                  ;See if special character
  2452. procstr_jmp:
  2453.         je    procstr_3        ;Yes, process special char.
  2454. procstr_2:
  2455.         stosb                ;Store byte from string
  2456.         dec    ah
  2457.         jne    procstr_1
  2458. procstr_exit:
  2459.         xor    al,al            ;Force zero byte end.
  2460.         stosb
  2461.         pop    si
  2462.         pop    di
  2463.         mov    bl,BUFF_SIZE
  2464.         sub    bl,ah
  2465.         mov    ds:[di-1],bl        ;Store length of string
  2466.         pop    bx
  2467.         ret
  2468. ;
  2469. ;A percent sign has been found indicating a 'soft' parameter.  Three types of
  2470. ;soft parameters are allowed; command line parameter, environment variable,
  2471. ;and for loop parameter.
  2472. ;
  2473. procstr_3:
  2474.         lodsb                ;Get next character
  2475.         dec    cx
  2476.         cmp    al,"%"                  ;If double %, include one
  2477.         je    procstr_2        ;  in string.
  2478.         cmp    al,7fh            ;See if for loop var
  2479.         jne    procstr_32
  2480.         push    si
  2481.         mov    si,forloop_ptr        ;Get ptr to for loop string
  2482. procstr_30:
  2483.         lodsb
  2484.         cmp    al,0            ;If zero, end of string
  2485.         je    procstr_31
  2486.         stosb
  2487.         dec    ah            ;Dec buffer size counter
  2488.         jne    procstr_30        ;If buffer not full, continue
  2489. procstr_31:
  2490.         pop    si            ;Get back source string pointer
  2491.         jmp    short procstr_4
  2492. procstr_32:
  2493.         mov    dh,al            ;Copy and check to see if
  2494.         sub    dh,"0"                  ;  the next char is a number.
  2495.         jb    procstr_5        ;  If so, assume a line
  2496.         cmp    dh,9            ;  parameter.
  2497.         ja    procstr_5
  2498.         call    procstr_cmdl        ;Call cmd line param routine
  2499. procstr_4:
  2500.         or    ah,ah
  2501.         jne    procstr_1
  2502.         jmp    short procstr_exit    ;If at end of string, done
  2503. procstr_5:
  2504.         dec    si            ;Backup to 1st character
  2505.         inc    cx
  2506.         call    procstr_env
  2507.         jmp    short procstr_4
  2508. procstr_code    endp
  2509. procstr_end    =    $
  2510.  
  2511. ;-----------------------------------------------------------------------------
  2512. ; SUBLINEPARAM substitutes a parameter from the command line.
  2513. ; Entry:  ES:DI - pointer to buffer to copy the line parameter
  2514. ;         DH - binary number of the line parameter
  2515. ;         AH - size of buffer
  2516. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2517. ;         CX - remaining length of the buffer
  2518. ;-----------------------------------------------------------------------------
  2519. subparm_getmem    equ    [bx-6]
  2520. subparm_off    dw    0            ;Pointer to offset in COM file
  2521. subparm_size    dw    offset subparm_end - offset subparm_start
  2522. subparm_next    dw    0            ;Ptr to next routine to append
  2523. subparm_lnks    dw    2            ;Bytes in the dependancy header
  2524. subparm_start    =    $
  2525.         dw    offset getmember_next    ;Offset of called routine.
  2526.  
  2527. sublineparam    proc    near
  2528.         assume    cs:code,ds:code,es:code,ss:code
  2529.         push    bx
  2530.         call    sublineparam_1
  2531.         db    "DOS2X",0        ;Dummy %0 parameter for DOS 2x
  2532. sublineparam_1:
  2533.         pop    bx
  2534.         push    cx
  2535.         push    si
  2536.         push    ds
  2537.         mov    si,80h            ;Get ptr to cmd line
  2538.         xor    cx,cx
  2539.         mov    cl,[si]         ;Get number of chars in buffer.
  2540.         inc    si            ;Point to data
  2541.         add    dh,ds:shift_count    ;Add in shift count.
  2542.         or    dh,dh            ;Check count of param to find.
  2543.         jnz    sublineparam_12
  2544. ;
  2545. ;For parameter 0, attempt to look in the env block for the name of the prog.
  2546. ;
  2547.         push    ax            ;Save buffer size in AH
  2548.         mov    ah,30h            ;Get DOS version 
  2549.         int    21h            ;If DOS 2.x, program nane not
  2550.         cmp    al,2            ;  in the env segment.  Use
  2551.         pop    ax
  2552.         ja    sublineparam_10        ;  dunny name instead.
  2553.         lea    si,[bx]            ;Point to dummy parameter
  2554.         jmp    short sublineparam_2
  2555. sublineparam_10:
  2556.         push    es
  2557.         push    di
  2558.         mov    es,ds:[2ch]        ;Get segment of local env    
  2559.         xor    al,al
  2560.         xor    di,di
  2561.         mov    cx,8000h
  2562. sublineparam_11:
  2563.         repne    scasb            ;Find double zero
  2564.         scasb
  2565.         jne    sublineparam_11
  2566.         scasw                ;Scan to name
  2567.         mov    si,di            ;Copy pointer to name
  2568.         pop    di
  2569.         pop    es
  2570.         mov    ds,ds:[2ch]
  2571.         jmp    short sublineparam_2
  2572. sublineparam_12:
  2573.         call    subparm_getmem        ;Get pointer to proper word.
  2574.         jc    sublineparam_exit
  2575. sublineparam_2:
  2576.         lodsb                ;Get character from parameter
  2577.         cmp    al," "                  ;If space, parameter done
  2578.         jbe    sublineparam_exit
  2579.         stosb
  2580.         dec    ah            ;Dec buffer size counter
  2581.         jnz    sublineparam_2
  2582. sublineparam_exit:
  2583.         pop    ds
  2584.         pop    si
  2585.         pop    cx
  2586.         pop    bx
  2587.         ret
  2588. sublineparam    endp
  2589. subparm_end    =    $
  2590. ;-----------------------------------------------------------------------------
  2591. ; SUBENVVAR substitutes a parameter from the program environment block.
  2592. ; Entry:  DS:SI - pointer to enviroment variable.
  2593. ;      ES:DI - pointer to buffer.
  2594. ;         AH - size of buffer.
  2595. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2596. ;      DS:SI - pointer to the character after the line parameter number
  2597. ;         CX - remaining free bytes in the buffer.
  2598. ;-----------------------------------------------------------------------------
  2599. subenv_srchenv    equ    [bx-6]
  2600. subenv_off    dw    0            ;Pointer to offset in COM file
  2601. subenv_size    dw    offset subenv_end-offset subenv_start
  2602. subenv_next    dw    0            ;Ptr to next routine to append
  2603. subenv_lnks    dw    2            ;Bytes in the dependancy header
  2604. subenv_start    =    $
  2605.         dw    offset searchenv_next    ;Call to search environment blk
  2606.  
  2607. subenvvar    proc    near
  2608.         assume    cs:code,ds:code,es:code,ss:code
  2609.         push    bx
  2610.         call    subenvvar_0
  2611. subenvvar_0:
  2612.         pop    bx
  2613.         push    ds
  2614. ;
  2615. ;Compute the length of the variable name.
  2616. ;
  2617.         mov    cx,255
  2618.         push    di            ;Save pointer to internal buff
  2619.         mov    di,si            ;Compute the length of the
  2620.         mov    dx,cx            ;  environment variable by
  2621.         mov    al,"%"                  ;  searching for the trailing
  2622.         repne    scasb            ;  % sign.
  2623.         sub    dx,cx            ;Compute length of variable.
  2624.         dec    dx            ;Subtract % byte from length.
  2625.         mov    cx,di
  2626.         pop    di
  2627.         push    cx            ;Save ptr to end of var
  2628.         call    subenv_srchenv        ;Search environment block.
  2629.         jc    short subenvvar_exit    ;CF set, variable not found.
  2630. ;
  2631. ;Environment variable found. Substitute into string.
  2632. ;
  2633. subenvvar_1:
  2634.         lodsb                ;Get env var character
  2635.         or    al,al            ;Check for end of string
  2636.         je    subenvvar_exit
  2637.         stosb                ;Save character in string
  2638.         dec    ah            ;Dec buffer size count.
  2639.         jne    subenvvar_1        ;If buffer not full, continue
  2640. subenvvar_exit:
  2641.         pop    si            ;Restore string pointer
  2642.         pop    ds            ;Restore segment register
  2643.         pop    bx
  2644.         ret
  2645. subenvvar    endp
  2646. subenv_end    =    $
  2647.  
  2648. ;-----------------------------------------------------------------------------
  2649. ; SEARCH_ENV scans the environment block for a string.
  2650. ; Entry:  DS:SI - pointer to ASCII string
  2651. ;         DX - length of string
  2652. ; Exit:   DS:SI - points to first character of environment string
  2653. ;         CF - clear if string found
  2654. ;-----------------------------------------------------------------------------
  2655. searchenv_off    dw    0               ;Pointer to offset in COM file
  2656. searchenv_size    dw    offset searchenv_end - offset searchenv_start
  2657. searchenv_next    dw    0               ;Ptr to next routine to append
  2658. searchenv_lnks    dw    0
  2659. searchenv_start =    $
  2660.  
  2661. search_env    proc near
  2662.         assume    ds:nothing,es:nothing
  2663.         push    bx
  2664.         push    cx
  2665.         push    di
  2666.         push    es
  2667.         mov    es,environment_seg    ;Get seg of environment blk
  2668.         xor    di,di            ;Point ES:DI to environment.
  2669.         mov    bx,si            ;Save pointer to var name
  2670. search_env_1:
  2671.         mov    si,bx            ;Get back ptr to var name.
  2672.         mov    cx,dx            ;Compare env var to var in
  2673.         repe    cmpsb            ;  string.
  2674.         je    search_env_2        ;Variable found, exit loop
  2675.         xor    al,al            ;Find next environment var.
  2676.         mov    cx,-1            ;Scan the entire segment.
  2677.         repne    scasb
  2678.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  2679.         jne    search_env_1        ;  block. else, loop back.
  2680. search_env_not_found:
  2681.         mov    si,di            ;Point SI to end of env data
  2682.         push    es
  2683.         pop    ds
  2684.         stc
  2685.         jmp    short search_env_exit
  2686. search_env_2:
  2687. ;
  2688. ;Environment variable found. Point DS:SI to the string.
  2689. ;
  2690.         mov    si,di
  2691.         push    es            ;DS:SI points to env string
  2692.         pop    ds
  2693. search_env_3:
  2694.         lodsb                ;Move environment pointer past
  2695.         cmp    al,"="                  ;  the equals sign.
  2696.         jne    search_env_3
  2697.         cmp    byte ptr [si],0
  2698.         je    search_env_not_found
  2699. search_env_4:
  2700.         lodsb                ;Move pointer to first
  2701.         or    al,al            ;  non-space character.
  2702.         jb    search_env_5
  2703.         cmp    al," "
  2704.         jb    search_env_4
  2705. search_env_5:
  2706.         dec    si
  2707.         clc
  2708. search_env_exit:
  2709.         pop    es
  2710.         pop    di
  2711.         pop    cx
  2712.         pop    bx
  2713.         ret
  2714. search_env    endp
  2715. searchenv_end    =    $
  2716.  
  2717. ;----------------------------------------------------------------------------
  2718. ;EXTERNAL CMD  Routine used to launch programs from the COM file.
  2719. ; Entry   DS:SI - Pointer to the ASCIIZ program name
  2720. ;      ES:DI - Pointer to the ASCIIZ command line tail
  2721. ;----------------------------------------------------------------------------
  2722. extern_intcmd    equ    [bx-14]
  2723. extern_echomsg    equ    [bx-12]
  2724. extern_parspath equ    [bx-10]
  2725. extern_launch    equ    [bx-8]
  2726. extern_ifexits    equ    [bx-6]
  2727. extern_pathcnt    equ    [bx]
  2728. extern_path_var equ    [bx+1]
  2729. extern_file_ext equ    [bx+6]
  2730. extern_filename equ    [bx+15]
  2731. extern_filetail equ    [bx+17]
  2732. extern_lostmsg    equ    [bx+19]
  2733. extern_cmdparm    equ    [bx+46]
  2734. extern_pathflag    equ    [bx+49]
  2735. external_ptr    dw    0            ;Pointer to offset in COM file
  2736. external_size    dw    offset external_end - offset external_start
  2737. external_next    dw    0            ;Ptr to next routine to append
  2738. external_lnks    dw    10            ;Bytes in the dependancy header ;Number of routines called
  2739. external_start    =    $
  2740.         dw    intcmd_next        ;Call to launch COMMAND.COM
  2741.         dw    echo_msg_next        ;Call to display string
  2742.         dw    parsepath_next        ;Call to get part of path
  2743.         dw    launch_next        ;Call execute file
  2744.         dw    ifexist_next        ;Call to find file
  2745.  
  2746. external_code    proc    near
  2747.         assume    cs:code,ds:code
  2748.         push    bx
  2749.         call    external_0
  2750.         db    0            ;Cnt to track path search.
  2751.         db    "PATH="
  2752.         db    "COMEXEBAT"
  2753.         dw    0            ;Pointer to filename
  2754.         dw    0            ;Pointer to command line tail
  2755.         db    "Bad command or file name",13,10,0
  2756.         db    "/C "
  2757.         db    0            ;Flag for path search
  2758. external_0:
  2759.         pop    bx            ;Get pointer to local vars.
  2760.         mov    extern_filename,si    ;Save ptr to file name
  2761.         mov    extern_filetail,di    ;Save ptr to command line tail
  2762.         mov    dx,exec_buff         ;Get pointer to free buffer.
  2763.         add    dx,4            ;Make room for /C if needed.
  2764.         mov    byte ptr extern_pathflag,0
  2765.         mov    byte ptr extern_pathcnt,0
  2766. ;Parse path to generate filename.
  2767. external_1:
  2768.         mov    di,dx            ;Get ptr to start of buffer
  2769.         xor    cx,cx            ;Check to see if we need to
  2770.         or    cl,extern_pathcnt    ;  check the directorys in
  2771.         jne    external_19        ;  the path.
  2772. ;The first time through, parse the name without using the path.
  2773.         push    dx
  2774.         push    si
  2775.         xor    dx,dx            ;Assume default drive
  2776.         cmp    byte ptr [si+1],':'    ;See if drive specified    
  2777.         jne    external_11
  2778.         mov    dl,[si]
  2779.         and    dl,0dfh            ;Set to upper case
  2780.         sub    dl,'@'            ;Convert ASCII to number
  2781.         movsw                ;Copy drive letter
  2782.         add    word ptr extern_filename,2  ;Don't use drive in path
  2783. external_11:
  2784.         cmp    byte ptr [si],'\'    ;See if starting at root.
  2785.         je    external_110
  2786.         mov    al,'\'            ;Start at root dir
  2787.         stosb
  2788.         push    si
  2789.         mov    si,di            ;Get pointer to buffer.
  2790.         mov    ah,47h            ;Get current directory
  2791.         int    21h
  2792.         pop    si
  2793.         xor    al,al
  2794.         mov    cx,64
  2795.         repne    scasb            ;Find end of directory string
  2796.         dec    di
  2797.         cmp    byte ptr [di-1],'\'    ;Unless at root dir, add
  2798.         je     external_110
  2799.         mov    al,'\'
  2800.         stosb
  2801. external_110:
  2802.         xor    ax,ax
  2803. external_12:
  2804.         lodsb                ;Get a byte
  2805.         cmp    ax,2e2eh        ;See if we need to back up
  2806.         jne    external_13        ;  one directory.
  2807.         std
  2808.         mov    al,'\'            ;Scan backwards to erase    
  2809.         mov    cx,18            ;  last directory.
  2810.         repne    scasb
  2811.         repne    scasb
  2812.         cld
  2813.         inc    di
  2814.         jmp    short external_12
  2815. external_13:
  2816.         stosb    
  2817.         mov    ah,al            ;Copy last character.
  2818.         cmp    al,'\'            ;See if name specifies a path
  2819.         jne    external_14
  2820.         inc    byte ptr extern_pathflag
  2821. external_14:
  2822.         cmp    al,0
  2823.         jne    external_12
  2824. external_15:
  2825.         dec    di            ;Since DOS does not let the
  2826.         mov    dx,di            ;  user specify the file ext.
  2827.         std                ;  scan back to make sure one
  2828.         mov    cx,5            ;  is not attached.
  2829.         mov    al,'.'
  2830.         repne   scasb    
  2831.         cld
  2832.         jne    external_16
  2833.         inc    di
  2834.         mov    dx,di
  2835. external_16:
  2836.         mov    di,dx
  2837.         pop    si
  2838.         pop    dx
  2839.         jmp    short external_4
  2840. ;Parse the path string to search remaining directorys.
  2841. external_19:
  2842.         cmp    byte ptr extern_pathflag,0  ;If a complete path was
  2843.         jne    external_badcmd            ;  specified, don't search
  2844.         mov    si,extern_filename        ;  the path.
  2845.         call    extern_parspath
  2846.         jnc    external_2        ;If we have checked all
  2847. external_badcmd:
  2848.         lea    si,extern_lostmsg    ;  directories in the path,
  2849.         call    extern_echomsg        ;  display file not found msg.
  2850.         jmp    short external_exit
  2851.  
  2852. ;Append filename to the end of the path.
  2853. external_2:
  2854.         mov    cx,73            ;Max length of filename
  2855. external_3:
  2856.         lodsb
  2857.         cmp    al,' '                  ;See if end of word
  2858.         jbe    external_4
  2859.         cmp    al,'.'                  ;See if end of filename
  2860.         je    external_4
  2861.         stosb
  2862.         loop    external_3
  2863. external_4:
  2864.         mov    al,'.'                  ;Append '.' to filename
  2865.         stosb
  2866.         lea    si,extern_file_ext    ;Get pointer to extensions
  2867.         mov    cx,3            ;3 extension types COM EXE BAT
  2868. external_5:
  2869.         movsw                ;Append extension to filename
  2870.         movsb
  2871.         xor    al,al            ;Termainate with zero
  2872.         stosb
  2873.         push    dx
  2874.         push    si
  2875.         push    cx
  2876.         mov    si,dx            ;Get ptr to start of name
  2877.         call    extern_ifexits        ;Search for file
  2878.         pop    cx
  2879.         pop    si
  2880.         pop    dx
  2881.         jnc    external_6
  2882.         sub    di,4            ;Backup to file extension
  2883.         loop    external_5
  2884.         inc    byte ptr extern_pathcnt ;Look in the next path str
  2885.         jmp    external_1
  2886. external_6:
  2887.         cmp    cx,1            ;See if BAT extension
  2888.         jne    external_8
  2889.         lea    si,extern_cmdparm    ;Get pointer to /C
  2890.         sub    dx,3
  2891.         mov    di,dx            ;Get ptr to string buffer
  2892.         movsw                ;Copy /C param
  2893.         movsb
  2894.         xor    al,al
  2895.         mov    cx,252
  2896.         repne    scasb            ;Find end of filename
  2897.         mov    byte ptr [di-1],' '     ;Fill in zero with space
  2898.         mov    si,extern_filetail    ;Get ptr to command line tail
  2899.         cmp    [si-1],cl
  2900.         ja    external_7
  2901.         mov    cl,[si-1]        ;Get length of cmd line tail
  2902. external_7:
  2903.         rep    movsb
  2904.         mov    byte ptr [di],13    ;Append CR to cmd line.
  2905.         mov    si,dx            ;Get pointer to BAT filename
  2906.         mov    ax,di            ;Compute length of cmd line.
  2907.         sub    ax,dx
  2908.         mov    [si-1],al
  2909.         call    extern_intcmd        ;Launch COMMAND.COM
  2910.         jmp    short external_exit
  2911. external_8:
  2912.         mov    di,extern_filetail    ;Get ptr to command line tail
  2913.         dec    di            ;Back up to buffer length
  2914.         dec    byte ptr [di]        ;Sub CR from length
  2915.         push    di
  2916.         mov    si,dx            ;Get ptr to start of name
  2917.         call    extern_launch        ;Execute program
  2918.         pop    di
  2919.         inc    byte ptr [di]        ;Restore cmd line length
  2920. external_exit:
  2921.         pop    bx
  2922.         ret
  2923. external_code    endp
  2924. external_end    =    $
  2925.  
  2926. ;-----------------------------------------------------------------------------
  2927. ; PARSEPATH  Parses the PATH and returns a qualified directory from the path.
  2928. ; Entry:  ES:DI - pointer to destination buffer.
  2929. ;         CX - index into the path variable. (zero based.)
  2930. ; Exit:   ES:DI - pointer to ASCIIZ destination filename.
  2931. ;         CF - Set if past end of the path
  2932. ;-----------------------------------------------------------------------------
  2933. parsepath_srenv equ    [bx-6]
  2934. parsepath_off    dw    0             ;Pointer to offset in COM file
  2935. parsepath_size    dw    offset parsepath_end - offset parsepath_start
  2936. parsepath_next    dw    0             ;Ptr to next routine to append
  2937. parsepath_lnks    dw    2
  2938. parsepath_start =    $
  2939.         dw    offset searchenv_next     ;Call to search env block
  2940.  
  2941. parsepath    proc    near
  2942.         assume    cs:code,ds:code,es:code,ss:code
  2943.         push    bx
  2944.         call    parsepath_1
  2945.         db    "PATH"
  2946. parsepath_1:
  2947.         pop    bx        
  2948.         push    dx
  2949.         push    si
  2950.         push    ds
  2951.         mov    dx,4            ;Length of PATH string
  2952.         mov    si,bx            ;Point SI to PATH string
  2953.         call    getcom_srchenv        ;PATH var ptr return in DS:SI
  2954. parsepath_2:
  2955.         dec    cx            ;Dec path segment count
  2956.         jcxz    parsepath_4
  2957. parsepath_3:
  2958.         lodsb                ;Get character
  2959.         or    al,al            ;See if end of path string
  2960.         je    parsepath_notfound
  2961.         cmp    al,';'                  ;See if end of path segment
  2962.         jne    parsepath_3
  2963.         jmp    short parsepath_2
  2964. parsepath_4:
  2965.         lodsb
  2966.         cmp    al,';'                  ;See if end of path segment
  2967.         je    parsepath_5
  2968.         or    al,al            ;See if end of path
  2969.         je    parsepath_5
  2970.         stosb
  2971.         jmp    short parsepath_4
  2972. parsepath_5:
  2973.         push    cs
  2974.         pop    ds
  2975.         cmp    byte ptr es:[di-1],'\'  ;Append \ if necessary.
  2976.         je    parsepath_6
  2977.         mov    al,'\'
  2978.         stosb
  2979. parsepath_6:
  2980.         clc
  2981. parsepath_exit:
  2982.         pop    ds
  2983.         pop    si
  2984.         pop    dx
  2985.         pop    bx
  2986.         ret
  2987. parsepath_notfound:
  2988.         stc
  2989.         jmp    short parsepath_exit
  2990. parsepath    endp
  2991. parsepath_end      =      $
  2992.  
  2993. ;-----------------------------------------------------------------------------
  2994. ; INTCMD  Launches the shell ,usually COMMAND.COM, to run an internal command.
  2995. ; Entry   DS:SI - pointer to the ASCIIZ internal command to run.
  2996. ;-----------------------------------------------------------------------------
  2997. intcmd_launch    equ    [bx-8]
  2998. intcmd_getcom    equ    [bx-6]
  2999. intcmd_off    dw     0            ;Pointer to offset in COM file
  3000. intcmd_size    dw     offset intcmd_end - offset intcmd_start
  3001. intcmd_next    dw     0            ;Ptr to next routine to append
  3002. intcmd_lnks    dw     4
  3003. intcmd_start    =      $
  3004.         dw     offset launch_next    ;Call to load and run program.
  3005.         dw     offset getcom_next    ;Call to find shell name.
  3006.  
  3007. intcommand    proc    near
  3008.         assume    cs:code,ds:code,es:code,ss:code
  3009.         push    bx
  3010.         call    intcmd_1
  3011. intcmd_1:
  3012.         pop    bx            ;Get pointer to sub calls.
  3013.         mov    di,si            ;Copy ptr to command
  3014.         dec    di            ;Back up to cmd line size.
  3015.         mov    al,process_rc        ;Get and save return code
  3016.         push    ds
  3017.         push    ax
  3018.         call    intcmd_getcom        ;Get comspec string.
  3019.         call    cs:intcmd_launch    ;Run program.
  3020.         pop    ax
  3021.         pop    ds
  3022.         mov    process_rc,al        ;Restore return code    
  3023.         pop    bx
  3024.         ret
  3025. intcommand    endp
  3026. intcmd_end    =    $
  3027.  
  3028. ;-----------------------------------------------------------------------------
  3029. ; GETCOMSPEC  Gets the name of the shell program running
  3030. ; Exit:   DS:SI - pointer to the ASCIIZ name of the shell porgram.
  3031. ;-----------------------------------------------------------------------------
  3032. getcom_srchenv    equ    [bx-6]
  3033. getcom_off    dw    0             ;Pointer to offset in COM file
  3034. getcom_size    dw    offset getcom_end - offset getcom_start
  3035. getcom_next    dw    0             ;Ptr to next routine to append
  3036. getcom_lnks    dw    2
  3037. getcom_start    =    $
  3038.         dw    offset searchenv_next     ;Call to search environment blk
  3039.  
  3040. getcomspec    proc    near
  3041.         assume    cs:code,ds:code,es:code,ss:code
  3042.         push    bx
  3043.         call    getcom_1
  3044. getcom_str    db    "COMSPEC"
  3045. getcom_1:
  3046.         pop    bx
  3047.         mov    dx,offset getcom_1 - offset getcom_str
  3048.         mov    si,bx
  3049.         call    getcom_srchenv        ;Get pointer to comspec string
  3050.         pop    bx
  3051.         ret
  3052. getcomspec    endp
  3053. getcom_end    =    $
  3054.  
  3055. ;----------------------------------------------------------------------------
  3056. ;LAUNCH PROG  Routine used to load and run programs.
  3057. ; Entry   DS:SI - pointer to the program name to run.
  3058. ;      ES:DI - pointer to the command line tail.
  3059. ; Exit      return code variable set.
  3060. ;----------------------------------------------------------------------------
  3061. launch_fcb1    equ    [bx]
  3062. launch_fcb2    equ    [bx+16]
  3063. launch_ptr    dw    0            ;Pointer to offset in COM file
  3064. launch_size    dw    offset launch_end - offset launch_start
  3065. launch_next    dw    0            ;Ptr to next routine to append
  3066. launch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  3067. launch_start    =    $
  3068.  
  3069. launch_code    proc    near
  3070.         assume    cs:code,ss:code
  3071.         push    bx
  3072.         call    launch_1        ;Push IP on stack
  3073.         db    0            ;Dummy FCB for program
  3074.         db    "DUMMY   FCB"
  3075.         db    0,0,0,0
  3076.         db    0            ;Dummy FCB for program
  3077.         db    "DUMMY   FCB"
  3078.         db    0,0,0,0
  3079. launch_1:
  3080.         pop    bx            ;Get pointer to local vars.
  3081.  
  3082.         push    ds
  3083.         push    es            ;Save stack ptr since it is not
  3084.         mov    com_stack_ptr,sp    ;  saved under DOS 2.x.
  3085. ;Parse first two parameters into FCBs.
  3086.         push    di            ;Save ptr to tail
  3087.         push    si            ;Save ptr to name
  3088.         mov    si,di            ;Copy ptr to cmd line
  3089.         inc    si            ;Skip size byte
  3090.         lea    di,launch_fcb1
  3091.         mov    ax,2903h        ;Parse FCB
  3092.         int    21h
  3093.         lea    di,launch_fcb2
  3094.         mov    ax,2903h
  3095.         int    21h
  3096.         pop    si
  3097.         pop    di
  3098.  
  3099.         push    cs            ;Create Parameter block on
  3100.         lea    dx,launch_fcb2        ;  the stack. Start with 2nd
  3101.         push    dx            ;  FCB.
  3102.         push    cs
  3103.         lea    dx,launch_fcb1
  3104.         push    dx
  3105.         push    cs            ;Push ptr to command line tail.
  3106.         push    di
  3107.         mov    ax,cs:[environment_seg]    ;Use env block set by prog.
  3108.         push    ax
  3109.         mov    bx,sp            ;Copy pointer to parameter blk
  3110.  
  3111.         mov    ax,4b00h        ;DOS EXEC program.
  3112.         mov    dx,si            ;Get pointer to filename
  3113.         int    21h
  3114.         mov    bp,offset data_start_ptr - offset init_code + 100h
  3115.         mov    bp,cs:[bp]
  3116.         mov    bx,cs            ;Reload BP to access local data
  3117.         cli
  3118.         mov    ss,bx            ;Restore stack
  3119.         mov    sp,com_stack_ptr
  3120.         sti
  3121.         cld                ;Restore default direction
  3122.         pop    es
  3123.         pop    ds
  3124. ;Get return code
  3125.         mov    ah,4dh            ;Get return code
  3126.         int    21h
  3127.         mov    process_rc,al        ;Save
  3128.         pop    bx
  3129.         ret
  3130. launch_code    endp
  3131. launch_end    =       $
  3132.  
  3133. ;----------------------------------------------------------------------------
  3134. ;GOTO  Routine to jump to a label pointed to by a cmd line parameter or
  3135. ;      environment variable.
  3136. ; Entry   DS:SI - pointer to label to find.
  3137. ;            DI - Wait flag/ptr. If <> 0, put goto address at pointer.
  3138. ; Exit      This routine does not return unless the label is not found.
  3139. ;----------------------------------------------------------------------------
  3140. goto_echomsg    equ    [bx-7]
  3141. goto_lblsrch    equ    [bx-5]
  3142. goto_ptr    dw    0            ;Pointer to offset in COM file
  3143. goto_size    dw    offset goto_end - offset goto_start
  3144. goto_next    dw    0            ;Ptr to next routine to append
  3145. goto_lnks    dw    4            ;Bytes in the dependancy header ;Number of routines called
  3146. goto_start    =    $
  3147.         dw    echo_msg_next        ;Used to print error msg
  3148.         dw    lblsrch_next        ;Used to find label
  3149.  
  3150. goto_code    proc    near
  3151.         assume    cs:code,ds:code
  3152.         call    goto_1
  3153.         db    8 dup (" ")
  3154.         db    " Label not found",13,10,0
  3155. goto_1:
  3156.         pop    bx
  3157.         push    di            ;Save wait flag/pointer
  3158.         mov    di,bx            ;Load label into error msg
  3159.         xor    dx,dx            ;Get size of label as it is
  3160.         mov    cx,8            ;  copied into error msg.
  3161. goto_2:
  3162.         lodsb
  3163.         cmp    al," "
  3164.         jbe    goto_4
  3165.         cmp    al,'a'
  3166.         jb    goto_3
  3167.         and    al,0dfh         ;Capitalize label
  3168.         cmp    al,'Z'
  3169.         ja    goto_4
  3170. goto_3:
  3171.         stosb
  3172.         inc    dx
  3173.         loop    goto_2
  3174. goto_4:
  3175.         mov    cx,dx            ;Get size of label
  3176.         mov    si,bx            ;Get pointer to label
  3177.         mov    di,com_label_start    ;Get ptr to start of label list
  3178.         add    di,bp            ;Add offset of data
  3179.         push    bx            ;Save ptr to msg
  3180.         call    goto_lblsrch        ;Call search routine
  3181.         pop    dx            ;Restore ptr to message
  3182.         pop    si            ;Restore Wait flag/pointer
  3183.         jc    goto_5            ;CF set, label not found.
  3184.         mov    ax,[bx+2]        ;Get destination ptr
  3185.         or    si,si            ;See if delay flag <> 0
  3186.         je    goto_41            ;If 0, no delay
  3187.         mov    [bp+si],ax        ;Save ret addr at pointer
  3188.         ret
  3189. goto_41:
  3190.         pop    ax            ;Remove return address
  3191.         push    [bx+2]            ;Push new return address
  3192. goto_exit:
  3193.         ret
  3194. goto_5:
  3195.         mov    bx,dx            ;Set addressability to call
  3196.         call    goto_echomsg        ;Print error message.
  3197.         ret
  3198. goto_code    endp
  3199. goto_end         =    $
  3200.  
  3201. ;----------------------------------------------------------------------------
  3202. ;GOTO DLY  Routine used if goto statment is inside a FOR loop.  Since a for
  3203. ;      loop cannot be exited before it ends, this routine checks to see if
  3204. ;      the GOTO statment was ever executed. If so, we now can jump.
  3205. ; Entry   DS:SI - pointer to destination pointer. 0 = no jump.
  3206. ; Exit      This routine does not return unless the ptr = 0
  3207. ;----------------------------------------------------------------------------
  3208. gotodly_ptr    dw    0            ;Pointer to offset in COM file
  3209. gotodly_size    dw    offset gotodly_end - offset gotodly_start
  3210. gotodly_next    dw    0            ;Ptr to next routine to append
  3211. gotodly_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  3212. gotodly_start    =    $
  3213.  
  3214. gotodly_code    proc    near
  3215.         assume    cs:code,ds:code
  3216.         xor    ax,ax            ;Get pointer, test if zero.
  3217.         or    ax,[si]            ;If zero, return.  If not
  3218.         je    gotodly_exit        ;  push the new destination
  3219.         pop    bx            ;  on the stack and return.
  3220.         push    ax
  3221. gotodly_exit:
  3222.         ret
  3223. gotodly_code    endp
  3224. gotodly_end     =         $
  3225.  
  3226. ;----------------------------------------------------------------------------
  3227. ;LABEL SEARCH Routine to search list of labels to determine goto destination.
  3228. ; Entry   ES:DI - pointer to the first entry in the list. (Assume ES = DS)
  3229. ;      DS:SI - pointer to label to find.
  3230. ;         CX - Length of label
  3231. ; Exit         BX - pointer to matching list entry, or last entry if not found.
  3232. ;         CF - Set if label not found.
  3233. ;----------------------------------------------------------------------------
  3234. lblsrch_ptr    dw    0            ;Pointer to offset in COM file
  3235. lblsrch_size    dw    offset lblsrch_end - offset lblsrch_start
  3236. lblsrch_next    dw    0            ;Ptr to next routine to append
  3237. lblsrch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  3238. lblsrch_start    =    $
  3239.  
  3240. lblsrch_code    proc    near
  3241.         assume    cs:code,ds:code
  3242.         push    si
  3243.         mov    dx,si            ;Save ptr to label
  3244.         mov    ax,cx            ;Save label length
  3245.         mov    bx,di            ;Get ptr to list
  3246. lblsrch_1:
  3247.         mov    di,bx
  3248.         add    di,4            ;Move to label string
  3249.         mov    si,dx            ;Get ptr to new label
  3250.         mov    cx,ax            ;Get length of label
  3251.         cmp    [di],cl         ;Compare lengths of the labels
  3252.         jne    lblsrch_2
  3253.         inc    di            ;Skip past length byte
  3254.         repe    cmpsb            ;Compare labels.
  3255.         je    lblsrch_4
  3256. lblsrch_2:
  3257.         cmp    word ptr [bx],-1    ;See if at end of list
  3258.         je    lblsrch_3
  3259.         add    bx,[bx]         ;Point to next label
  3260.         jmp    short lblsrch_1
  3261. lblsrch_3:
  3262.         stc                ;No label found.
  3263.         jmp    short lblsrch_exit
  3264. lblsrch_4:
  3265.         clc                ;Label found
  3266. lblsrch_exit:
  3267.         pop    si
  3268.         ret
  3269. lblsrch_code    endp
  3270. lblsrch_end    =    $
  3271.  
  3272. ;-----------------------------------------------------------------------------
  3273. ; IFEQUAL  Compares two strings.
  3274. ; Entry:  DS:SI - Pointer to first ASCIIZ String
  3275. ;      ES:DI - Pointer to second ASCIIZ String
  3276. ;         CX - Length of strings.
  3277. ; Exit:      CF - Clear if equal
  3278. ;-----------------------------------------------------------------------------
  3279. ifequal_off    dw     0            ;Pointer to offset in COM file
  3280. ifequal_size    dw     offset ifequal_end - offset ifequal_start
  3281. ifequal_next    dw     0            ;Ptr to next routine to append
  3282. ifequal_lnks    dw     0
  3283. ifequal_start    =      $
  3284.  
  3285. ifequal     proc    near
  3286.         assume    cs:code,ds:code,es:code,ss:code
  3287.         xor    cx,cx
  3288.         mov    cl,[si-1]        ;Get size of string
  3289.         cmp    cl,[di-1]        ;Compare sizes of strings
  3290.         jne    ifequal_notequal
  3291.         rep    cmpsb            ;Compare strings
  3292.         jne    ifequal_notequal
  3293.         clc
  3294.         ret
  3295. ifequal_notequal:
  3296.         stc
  3297.         ret
  3298. ifequal     endp
  3299. ifequal_end    =    $
  3300.  
  3301. ;-----------------------------------------------------------------------------
  3302. ; IFEXIST  Determines if a file exists.
  3303. ; Entry:  DS:SI - Pointer to ASCIIZ filename.
  3304. ;         DI - Pointer to buffer for disk transfer area.
  3305. ; Exit:      CF - Clear if file exists
  3306. ;         DI - IF file exists, points to filename.
  3307. ;-----------------------------------------------------------------------------
  3308. ifexist_off    dw     0            ;Pointer to offset in COM file
  3309. ifexist_size    dw     offset ifexist_end - offset ifexist_start
  3310. ifexist_next    dw     0            ;Ptr to next routine to append
  3311. ifexist_lnks    dw     0
  3312. ifexist_start    =      $
  3313.  
  3314. ifexist     proc    near
  3315.         assume    cs:code,ds:code,es:code,ss:code
  3316.         mov    dx,di
  3317.         mov    ah,1ah            ;Set DTA
  3318.         int    21h
  3319.  
  3320.         mov    dx,si            ;Copy pointer to filename
  3321.         xor    cx,cx            ;Normal attributes
  3322.         mov    ah,4eh            ;DOS Find First
  3323.         int    21h
  3324.         jc    ifexist_exit
  3325.         add    di,1eh            ;Point DI to filename in DTA
  3326.         clc
  3327. ifexist_exit:
  3328.         ret
  3329. ifexist     endp
  3330. ifexist_end    =    $
  3331.  
  3332. ;-----------------------------------------------------------------------------
  3333. ; IFERRLEV  Compares the value passed with the return code of the last
  3334. ;        program executed.
  3335. ; Entry:     SI - Pointer to ASCIIZ Error level.
  3336. ; Exit:      CF - Clear if process error level above or equal to SI
  3337. ;-----------------------------------------------------------------------------
  3338. iferrlev_off    dw     0            ;Pointer to offset in COM file
  3339. iferrlev_size    dw     offset iferrlev_end - offset iferrlev_start
  3340. iferrlev_next    dw     0            ;Ptr to next routine to append
  3341. iferrlev_lnks    dw     0
  3342. iferrlev_start    =      $
  3343.  
  3344. iferrlev    proc    near
  3345.         assume    cs:code,ds:code,es:code,ss:code
  3346.         xor    ax,ax            ;Convert ASCIIZ number into
  3347.         mov    bx,ax            ;  decimal
  3348. iferrlev_1:
  3349.         mov    bl,[si]         ;Convert error level number
  3350.         sub    bl,'0'                  ;  from ASCII to decimal.
  3351.         jb    iferrlev_2
  3352.         cmp    bl,9
  3353.         ja    iferrlev_2
  3354.         mov    dx,10
  3355.         mul    dx
  3356.         jc    iferrlev_2
  3357.         add    ax,bx            ;Add in digit
  3358.         inc    si
  3359.         jmp    short iferrlev_1
  3360. iferrlev_2:
  3361.         cmp    process_rc,al        ;Compare to last program
  3362.         ret
  3363. iferrlev    endp
  3364. iferrlev_end    =    $
  3365.  
  3366. ;-----------------------------------------------------------------------------
  3367. ; FORLOOP  Processes commands in a FOR loop.
  3368. ; Entry:     SI - Pointer to ASCIIZ set of parameters.
  3369. ;         DI - Pointer loop structure in data area
  3370. ;          LoopCnt    db     0    Member of the set to use
  3371. ;          FirstFlag    db     0    Indicates Find first/next
  3372. ; Exit:      CF - Set if FOR loop complete.
  3373. ;-----------------------------------------------------------------------------
  3374. forloop_getmem    equ    [bx-6]
  3375. forloop_savchr    equ    [bx]
  3376. forloop_eptr    equ    [bx+1]
  3377. forloop_dta       equ    [bx+3]
  3378. forloop_off    dw    0            ;Pointer to offset in COM file
  3379. forloop_size    dw    offset forloop_end - offset forloop_start
  3380. forloop_next    dw    0            ;Ptr to next routine to append
  3381. forloop_lnks    dw    2
  3382. forloop_start    =    $
  3383.         dw    getmember_next
  3384.  
  3385. forloop     proc    near
  3386.         assume    cs:code,ds:code,es:code,ss:code
  3387.         push    bx
  3388.         call    forloop_0
  3389.         db    0            ;Saved termaination character
  3390.         dw    0            ;Ptr to term character address
  3391.         db    43 dup (0)        ;Used for DTA
  3392. forloop_0:
  3393.         pop    bx
  3394.         push    si
  3395.         mov    si,forloop_eptr
  3396.         or    si,si
  3397.         je    forloop_01
  3398.         mov    al,forloop_savchr
  3399.         mov    byte ptr [si-1],al     ;Remove zero terminator
  3400. forloop_01:
  3401.         pop    si
  3402. ;
  3403. ;Set DTA. If 2nd time or later time looping on a member, use find next to
  3404. ;determine the string for this time through the loop.
  3405. ;
  3406.         lea    dx,forloop_dta        
  3407.         mov    ah,1ah            ;Set DTA
  3408.         int    21h
  3409.  
  3410.         cmp    byte ptr [di+1],0    ;See if first time for member
  3411.         je    forloop_1
  3412.         mov    ah,4fh            ;Find next file
  3413.         int    21h
  3414.         jc    forloop_1        ;Not found, go to next member
  3415.         lea    dx,[bx+21h]        ;Point to filename in DTA
  3416.         jmp    short forloop_notdone    ;Execute loop body
  3417. ;
  3418. ;First time with this member of the set, if wildcards are in the member,
  3419. ;use DOS find first to get the loop string.
  3420. ;
  3421. forloop_1:
  3422.         mov    byte ptr [di+1],0    ;Clear first/next flag
  3423.         inc    byte ptr [di]        ;Look at next member of the set
  3424.         mov    dh,[di]         ;Get loop count
  3425.         call    forloop_getmem        ;Get member of set.  If no
  3426.         jc    forloop_done        ;  more members, loop done.
  3427.         mov    dx,si            ;Save pointer to member
  3428.         xor    ah,ah            ;Clear wildcard flag
  3429. forloop_2:
  3430.         lodsb                ;Scan set member to check for
  3431.         cmp    al,' '                  ;  any wildcard chars.
  3432.         jbe    forloop_4
  3433.         cmp    al,'?'
  3434.         jne    forloop_3
  3435.         inc    ah            ;Set wildcard found flag
  3436. forloop_3:
  3437.         cmp    al,'*'
  3438.         jne    forloop_2
  3439.         inc    ah            ;Set wildcard found flag
  3440.         jmp    short forloop_2
  3441. forloop_4:
  3442.         xor    al,al
  3443.         xchg    byte ptr [si-1],al    ;Set zero terminator.
  3444.         mov    forloop_savchr,al    ;Save char over written
  3445.         or    ah,ah            ;If no wildcards, execute
  3446.         je    forloop_notdone     ;Execute loop body
  3447.         mov    byte ptr [di+1],1    ;Set first/next flag
  3448.         xor    cx,cx            ;Normal attributes
  3449.         mov    ah,4eh            ;DOS find first
  3450.         int    21h
  3451.         jc    forloop_1        ;If not found, get next member
  3452.         lea    dx,[bx+1eh]        ;Set ptr to filename in DTA
  3453. forloop_notdone:
  3454.         mov    forloop_ptr,dx        ;Set loop data ptr
  3455.         mov    forloop_eptr,si
  3456.         clc
  3457. forloop_exit:
  3458.         pop    bx
  3459.         ret
  3460. forloop_done:
  3461.         mov    word ptr [di],0     ;Clear loop variables
  3462.         mov    word ptr forloop_eptr,0
  3463.         stc
  3464.         jmp    short forloop_exit
  3465. forloop     endp
  3466. forloop_end    =    $
  3467.  
  3468. ;-----------------------------------------------------------------------------
  3469. ; FINDENV  Finds the master environment block.
  3470. ; Exit:    Variable Environment_seg set with segment of master environment.
  3471. ;-----------------------------------------------------------------------------
  3472. findenv_dosver    equ    [bx+7]
  3473. findenv_cmdname equ    [bx]
  3474. findenv_off    dw    0             ;Pointer to offset in COM file
  3475. findenv_size    dw    offset findenv_end - offset findenv_start
  3476. findenv_next    dw    0             ;Ptr to next routine to append
  3477. findenv_lnks    dw    0
  3478. findenv_start    =    $
  3479.  
  3480. findenv     proc    near
  3481.         assume    cs:code,ds:code,es:code,ss:code
  3482.         push    bx
  3483.         call    findenv_0
  3484.  
  3485.         db    "COMMAND"
  3486.         dw    0
  3487. findenv_0:
  3488.         pop    bx
  3489.         push    es
  3490.  
  3491.         mov    ax,ds:[2ch]        ;Get default env
  3492.         cmp    environment_seg,ax    ;Check to see if already
  3493.         jne    findenv_jmp_exit    ;  found.
  3494.  
  3495.         push    bx            ;Ver changes BX
  3496.         mov    ah,30h            ;Get dos Version
  3497.         int    21h
  3498.         xchg    al,ah
  3499.         mov    findenv_dosver,ax
  3500.  
  3501.         mov    ah,52h            ;get address of first MCB
  3502.         int    21h
  3503.         mov    ax,es:[bx-2]        ;point ES to MCB
  3504.         mov    cx,20            ;Allow only 20 loops.
  3505.         pop    bx
  3506. findenv_1:
  3507.         mov    es,ax
  3508.         cmp    byte ptr es:[0],"M"     ;check for mcb signature
  3509.         jne    short findenv_exit
  3510.         inc    ax            ;point AX to memory block
  3511.         cmp    ax,es:[1]        ;See if this is a PSP block
  3512.         je    findenv_4
  3513. findenv_2:
  3514.         add    ax,es:[3]        ;Get size of memory block
  3515.         loop    findenv_1
  3516. findenv_jmp_exit:
  3517.         jmp    short findenv_exit
  3518. findenv_4:
  3519.         cmp    word ptr findenv_dosver,0a00h ;If OS/2, use DOS 3.3 method.
  3520.         jae    findenv_5
  3521.         cmp    word ptr findenv_dosver,0400h;If DOS 4.00 or greater,
  3522.         jb    findenv_5          ;  COMMAND.COM may not be the
  3523.         push    ds              ;  first program loaded.  Look
  3524.         lea    si,findenv_cmdname      ;  at the name of the program
  3525.         mov    di,8              ;  stored in the last 8 bytes
  3526.         mov    cx,7              ;  of the memory control
  3527.         repe    cmpsb              ;  block.  If the string
  3528.         pop    ds              ;  "COMMAND" isn't found,
  3529.         jne    findenv_2          ;  keep looking.
  3530. findenv_5:
  3531.         mov    dx,ax            ;Save PSP seg of command.com
  3532.         mov    es,ax
  3533.         mov    bx,es:[2ch]        ;Get seg of prog environment
  3534.         mov    ax,bx
  3535.         dec    bx
  3536.         mov    es,bx
  3537.         cmp    byte ptr es:[0],"M"     ;See if valid memory block
  3538.         je    findenv_found
  3539.         mov    ax,dx            ;Get back cmd.com segment
  3540.         dec    ax            ;Point back to mcb
  3541.         mov    es,ax
  3542. findenv_6:
  3543.         add    ax,es:[3]        ;If master env segment not 
  3544.         inc    ax            ;  saved at 2Ch of the PSP, 
  3545.         mov    es,ax            ;  scan the memory blocks
  3546.         cmp    es:[1],dx        ;  for first segment
  3547.         je    findenv_7        ;  owned by command.com.
  3548.         loop    findenv_6
  3549.         jmp    short findenv_exit    ;Master env not found.
  3550. findenv_7:    
  3551.         inc    ax            ;Point AX to env segment
  3552. findenv_found:
  3553.         mov    environment_seg,ax    ;Save pointer to master env 
  3554. findenv_exit:
  3555.         pop    es
  3556.         pop    bx
  3557.         ret
  3558. findenv     endp
  3559. findenv_end    =    $
  3560.  
  3561. ;-----------------------------------------------------------------------------
  3562. ; SET_ENV  Sets/resets environment variables.
  3563. ; Entry:  DS:SI - pointer to ASCII string containing the environment variable
  3564. ;          and, optionally, the string to assign.
  3565. ;                 If no string specified, the environment is dumped to the
  3566. ;                 screen.
  3567. ;            DI - Flag to indicate setting of PATH and PROMPT vars
  3568. ;                 0 = Normal Env var, 1 = PROMPT var, 2 = PATH var.
  3569. ;-----------------------------------------------------------------------------
  3570. setenv_findenv    equ    [bx-10]
  3571. setenv_echo    equ    [bx-8]
  3572. setenv_serchenv equ    [bx-6]
  3573. setenv_pathflag    equ    [bx]
  3574. setenv_varlen     equ    [bx+1]
  3575. setenv_fullmsg    equ    [bx+2]
  3576. setenv_crmsg      equ    [bx+29]
  3577. setenv_nopath    equ    [bx+32]
  3578. setenv_off    dw    0            ;Pointer to offset in COM file
  3579. setenv_size    dw    offset setenv_end - offset setenv_start
  3580. setenv_next    dw    0            ;Ptr to next routine to append
  3581. setenv_lnks    dw    6
  3582. setenv_start    =    $
  3583.         dw    offset findenv_next    ;Call to find the master env
  3584.         dw    offset echo_msg_next    ;Call to print line.
  3585.         dw    offset searchenv_next    ;Call to search environment blk
  3586.  
  3587. set_env     proc near
  3588.         assume    ds:nothing,es:nothing
  3589.         push    bx
  3590.         call    setenv_1
  3591.         db    0            ;PATH/PROMPT flag storage
  3592.         db    0            ;Var length.
  3593.         db    "Out of environment space",13,10,0
  3594.         db    13,10,0
  3595.         db    "No Path",0
  3596. setenv_1:
  3597.         pop    bx            ;Set up local addressing
  3598.         mov    ax,di
  3599.         xchg    al,ah
  3600.         mov    setenv_pathflag,ah
  3601.         push    ax
  3602.         call    setenv_findenv        ;Find master env block
  3603.         pop    ax
  3604.         push    bp
  3605.         push    es
  3606. ;See if we need to simply print the PATH statment.
  3607.         cmp    ah,3
  3608.         jne    setenv_19
  3609.         mov    dx,4
  3610.         call    setenv_serchenv     ;Get pointer to variable
  3611.         jnc    setenv_11
  3612.         lea    si,setenv_nopath    ;If path string not found, 
  3613.         push    cs            ;  print no path msg.
  3614.         pop    ds
  3615.         jmp    short setenv_12
  3616. setenv_11:
  3617.         sub    si,5            ;Back up to start of PATH
  3618. setenv_12:
  3619.         call    cs:setenv_echo        ;Print string
  3620.         push    cs
  3621.         pop    ds
  3622.         lea    si,setenv_crmsg        ;Append CR.
  3623.         call    setenv_echo
  3624.         jmp    setenv_8
  3625. setenv_19:    
  3626.         mov    cx,BUFF_SIZE
  3627.         xor    dx,dx
  3628.         push    si            ;Save ptr to new env var
  3629.         mov    di,si
  3630. setenv_2:
  3631.         lodsb
  3632.         or     ah,ah            ;See if PATH or PROMPT
  3633.         je    setenv_23
  3634.         cmp    al," "            ;If PATH or PROMPT statments,
  3635.         jne    setenv_23        ;  remove any spaces between    
  3636.         mov    al,"="            ;  variable and assignment.
  3637.         push    di
  3638.         stosb
  3639. setenv_20:
  3640.         lodsb                ;Scan past equal sign 
  3641.         cmp    al," "            
  3642.         je    setenv_20
  3643.         cmp    al,"="
  3644.         je    setenv_20
  3645. setenv_21:
  3646.         stosb    
  3647.         or    al,al
  3648.         je    setenv_22
  3649.         lodsb                ;Remove spaces in set string.
  3650.         jmp    short setenv_21
  3651. setenv_22:
  3652.         pop    di
  3653.         jmp    short setenv_4
  3654. setenv_23:
  3655.         or     al,al
  3656.         je    setenv_4
  3657.         cmp    al,"="                  ;Scan until end of variable
  3658.         je    setenv_4        ;  found.
  3659.         cmp    al,'a'
  3660.         jb    setenv_3
  3661.         cmp    al,'z'
  3662.         ja    setenv_3
  3663.         and    al,0dfh         ;Capitalize variable
  3664. setenv_3:
  3665.         cmp    al," "            ;Keep a count of non-space
  3666.         jbe    setenv_31        ;  characters.
  3667.         inc    dh
  3668. setenv_31:
  3669.         stosb
  3670.         inc    dl            ;Var length count.
  3671.         loop    setenv_2
  3672. setenv_4:
  3673.         pop    si
  3674. ;
  3675. ;If no characters after SET, dump env vars to screen.
  3676. ;
  3677.         mov    setenv_varlen,dl    ;Save length of env var.
  3678.         mov    al,dh
  3679.         xor    dh,dh
  3680.         or    dh,dh            ;See if path or prompt
  3681.         jne    setenv_40
  3682. setenv_40:
  3683.         or    al,al            ;If second Zero, end of vars.
  3684.         jne    setenv_48
  3685.         push    ds
  3686.         mov    ds,cs:[environment_seg]    ;Get segment of environment
  3687.         xor    si,si
  3688.         lea    di,setenv_crmsg        ;Get address of CR string
  3689.         mov    cx,cs
  3690. setenv_41:
  3691.         call    cs:setenv_echo        ;Print var
  3692.         push    ds
  3693.         push    si
  3694.         mov     ds,cx
  3695.         mov     si,di
  3696.         call    cs:setenv_echo        ;Print CR
  3697.         pop    si
  3698.         pop    ds
  3699.         cmp    byte ptr ds:[si],0    ;If next char 0, end of block
  3700.         jne    setenv_41
  3701.         pop    ds
  3702.         jmp    setenv_8
  3703. ;
  3704. ;Set or Clear env var.
  3705. ;
  3706. setenv_48:
  3707.         mov    ax,si
  3708.         inc    di
  3709.         cmp    byte ptr cs:[di]," "    ;If nothing past '=' then
  3710.         jae    setenv_49        ;  simply erase var from env.
  3711.         xor    ax,ax
  3712. setenv_49:
  3713.         push    ax            ;Save set/erase flag
  3714.         call    setenv_serchenv     ;Get pointer to variable
  3715.         pop    dx            
  3716.         push    ds            ;ES = env segment
  3717.         pop    es
  3718.         mov    di,si            ;Copy pointer to variable
  3719.         jc    setenv_61
  3720.  
  3721.         xor    al,al            ;Scan backwards to find start
  3722.         std                ;  of var name
  3723.         mov    cx,256
  3724.         repne    scasb
  3725.         inc    di
  3726.         inc    di
  3727.         push    di
  3728.         cld                ;Scan forward to find end of
  3729.         mov    cx,256            ;  variable.
  3730.         repne    scasb
  3731.         mov    si,di
  3732.         pop    di
  3733.         xor    ah,ah
  3734. setenv_5:
  3735.         lodsb                ;Move byte from past var to
  3736.         stosb                ;  cover up current assignment
  3737.         or    ah,al            ;If two zeros in a row then
  3738.         je    setenv_6        ;  end of env vars.
  3739.         mov    ah,al
  3740.         jmp    short setenv_5
  3741. setenv_6:
  3742.         dec    di            ;Back up before last zero
  3743. setenv_61:
  3744.         push    cs
  3745.         pop    ds
  3746.         mov    si,dx            ;Get back ptr to env var
  3747.         or    si,si            ;See if var assignment
  3748.         je    setenv_8
  3749.  
  3750.         push    es            ;Get size of the environment
  3751.         mov    ax,es            ;  block by reading the size
  3752.         dec    ax            ;  in the memory control block.
  3753.         mov    es,ax
  3754.         mov    bp,es:[3]
  3755.         mov    cl,4
  3756.         shl    bp,cl            ;Convert to bytes.
  3757.         dec    bp
  3758.         dec    bp
  3759.         pop    es
  3760.         xor    ax,ax            ;See if there is room in the
  3761.         mov    al,setenv_varlen    ;  env block for the var name.
  3762.         inc    al            ;  If not, don't even start.
  3763.         add    ax,di            ;  If room for name, copy as 
  3764.         cmp    ax,bp            ;  much of the var as possible
  3765.         jae    setenv_72
  3766.         mov    ah,setenv_pathflag    ;Get pathflag byte
  3767. setenv_7:
  3768.         cmp    di,bp            ;Check for end of env block.
  3769.         jae    setenv_72
  3770.         lodsb                ;Copy new env var
  3771.         cmp    ah,2    
  3772.         jne    setenv_71        ;If PATH var, make upper case.
  3773.         cmp    al,'a'
  3774.         jb     setenv_71
  3775.         cmp    al,'z'
  3776.         ja    setenv_71
  3777.         and    al,0dfh            
  3778. setenv_71:    
  3779.         stosb
  3780.         or    al,al            ;Check for end of variable.
  3781.         jne    setenv_7
  3782.         stosb
  3783.         jmp    short setenv_8
  3784. setenv_72:
  3785.         xor    al,al
  3786.         stosb
  3787.         push    cs
  3788.         pop    es
  3789.         lea    si,setenv_fullmsg    ;If environment block full,
  3790.         call    setenv_echo        ;  print message.
  3791. setenv_8:
  3792.         pop    es
  3793.         pop    bp
  3794.         pop    bx
  3795.         ret
  3796. set_env     endp
  3797. setenv_end    =    $
  3798.  
  3799. ;-----------------------------------------------------------------------------
  3800. ; REDIROO  Opens a file for output redirection.
  3801. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3802. ;         DI - 0  open new file, 1 append to existing file.
  3803. ;-----------------------------------------------------------------------------
  3804. rediroo_off    dw    0            ;Pointer to offset in COM file
  3805. rediroo_size    dw    offset rediroo_end - offset rediroo_start
  3806. rediroo_next    dw    0            ;Ptr to next routine to append
  3807. rediroo_lnks    dw    0
  3808. rediroo_start    =    $
  3809.  
  3810. rediroo     proc near
  3811.         assume    ds:nothing,es:nothing
  3812.  
  3813.         mov    word ptr stdout_hdl,-1    ;Clear handle
  3814.         mov    dx,si            ;Get ptr to outfile file
  3815.         xor    cx,cx            ;Normal attributes
  3816.         mov    ax,3c02h        ;Create file
  3817.         or    di,di            ;See if append or new file
  3818.         je    rediroo_2
  3819.         inc    ah            ;Open file
  3820. rediroo_2:
  3821.         int    21h
  3822.         jc    rediroo_exit
  3823.         mov    bx,ax            ;Copy file handle
  3824.         or    di,di
  3825.         je    rediroo_3
  3826.         mov    ax,4202h        ;Move file ptr to end of file
  3827.         xor    dx,dx
  3828.         mov    cx,dx
  3829.         int    21h
  3830.         jc    rediroo_exit
  3831. rediroo_3:
  3832.         mov    outfile_hdl,bx        ;Save output file handle
  3833.         push    bx
  3834.         mov    ah,45h            ;Duplicate output handle
  3835.         mov    bx,1            ;Std output handle
  3836.         int    21h
  3837.         mov    stdout_hdl,ax        ;Save dup std output handle
  3838.  
  3839.         mov    cx,1
  3840.         pop    bx
  3841.         mov    ah,46h            ;Force dup file handle
  3842.         int    21h
  3843. rediroo_exit:
  3844.         ret
  3845. rediroo     endp
  3846. rediroo_end    =    $
  3847.  
  3848. ;-----------------------------------------------------------------------------
  3849. ; REDIRCO  Closes a file used for output redirection.
  3850. ;-----------------------------------------------------------------------------
  3851. redirco_off    dw    0            ;Pointer to offset in COM file
  3852. redirco_size    dw    offset redirco_end - offset redirco_start
  3853. redirco_next    dw    0            ;Ptr to next routine to append
  3854. redirco_lnks    dw    0
  3855. redirco_start    =    $
  3856.  
  3857. redirco     proc near
  3858.         assume    ds:nothing,es:nothing
  3859.         cmp    word ptr stdout_hdl,-1    ;If error on redirect, skip
  3860.         je    redirco_exit        ;  restore.
  3861.  
  3862.         mov    ah,46h            ;Force restore of std out
  3863.         mov    bx,stdout_hdl
  3864.         mov    cx,1
  3865.         int    21h
  3866.  
  3867.         mov    ah,3eh            ;Close file
  3868.         mov    bx,outfile_hdl        ;Get output file handle
  3869.         int    21h
  3870. redirco_exit:
  3871.         ret
  3872. redirco     endp
  3873. redirco_end    =    $
  3874.  
  3875. ;-----------------------------------------------------------------------------
  3876. ; REDIROI  Opens a file for input redirection.
  3877. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3878. ;         DI - 0  open new file, 1 append to existing file.
  3879. ;-----------------------------------------------------------------------------
  3880. rediroi_off    dw    0            ;Pointer to offset in COM file
  3881. rediroi_size    dw    offset rediroi_end - offset rediroi_start
  3882. rediroi_next    dw    0            ;Ptr to next routine to append
  3883. rediroi_lnks    dw    0
  3884. rediroi_start    =    $
  3885.  
  3886. rediroi     proc near
  3887.         assume    ds:nothing,es:nothing
  3888.  
  3889.         mov    word ptr stdin_hdl,-1    ;Clear handle
  3890.         mov    dx,si            ;Get ptr to outfile file
  3891.         mov    ax,3d00h        ;Open file, Read only
  3892.         int    21h
  3893.         jc    rediroi_exit
  3894.         mov    infile_hdl,ax        ;Save input file handle
  3895.         push    ax
  3896.  
  3897.         mov    ah,45h            ;Duplicate input handle
  3898.         xor    bx,bx
  3899.         int    21h
  3900.         mov    stdin_hdl,ax        ;Save dup std input handle
  3901.  
  3902.         xor    cx,cx
  3903.         pop    bx
  3904.         mov    ah,46h            ;Force dup file handle
  3905.         int    21h
  3906. rediroi_exit:
  3907.         ret
  3908. rediroi     endp
  3909. rediroi_end    =    $
  3910.  
  3911. ;-----------------------------------------------------------------------------
  3912. ; REDIRCI  Closes a file used for input redirection.
  3913. ;-----------------------------------------------------------------------------
  3914. redirci_off    dw    0            ;Pointer to offset in COM file
  3915. redirci_size    dw    offset redirci_end - offset redirci_start
  3916. redirci_next    dw    0            ;Ptr to next routine to append
  3917. redirci_lnks    dw    0
  3918. redirci_start    =    $
  3919.  
  3920. redirci     proc near
  3921.         assume    ds:nothing,es:nothing
  3922.         cmp    word ptr stdin_hdl,-1    ;If error on redirect, skip
  3923.         je    redirci_exit        ;  restore.
  3924.  
  3925.         mov    ah,46h            ;Force restore of std in hdl
  3926.         xor    cx,cx
  3927.         mov    bx,stdin_hdl
  3928.         int    21h
  3929.  
  3930.         mov    ah,3eh            ;Close file
  3931.         mov    bx,infile_hdl        ;Get input file handle
  3932.         int    21h
  3933. redirci_exit:
  3934.         ret
  3935. redirci     endp
  3936. redirci_end    =    $
  3937.  
  3938. ;-----------------------------------------------------------------------------
  3939. ; REDIRDEL Deletes piping file.
  3940. ; Entry:  DS:SI - pointer to ASCII filename to delete.
  3941. ;-----------------------------------------------------------------------------
  3942. redirdel_off    dw    0            ;Pointer to offset in COM file
  3943. redirdel_size    dw    offset redirdel_end - offset redirdel_start
  3944. redirdel_next    dw    0            ;Ptr to next routine to append
  3945. redirdel_lnks    dw    0
  3946. redirdel_start    =    $
  3947.  
  3948. redirdel     proc near
  3949.         assume    ds:nothing,es:nothing
  3950.  
  3951.         mov    dx,si            ;Copy pointer to filename
  3952.         mov    ah,41h            ;Delete file
  3953.         int    21h
  3954.         ret
  3955. redirdel     endp
  3956. redirdel_end    =    $
  3957.  
  3958. initialize    endp
  3959.         even                ;compiler stack on word boundry
  3960. end_of_code    =    $
  3961. code        ends
  3962.  
  3963. end        main
  3964. e.
  3965.         cmp    al,'a'
  3966.         jb     setenv_71
  3967.         cmp    al,'z'
  3968.         ja    setenv_71
  3969.         and    al,0dfh            
  3970. setenv_71:    
  3971.         stosb
  3972.